From 19212c25df55561b29f17e8919c083927eb59989 Mon Sep 17 00:00:00 2001 From: Peter Gromov Date: Tue, 1 Aug 2006 18:41:53 +0400 Subject: [PATCH] performance --- .../util/xml/impl/DomInvocationHandler.java | 86 ++++++++++++-------- .../util/xml/impl/FixedChildDescriptionImpl.java | 21 +---- .../intellij/util/xml/impl/GenericInfoImpl.java | 93 ++++++++++------------ .../xml/impl/GenericValueReferenceProvider.java | 27 ++++--- .../xml/impl/IndexedElementInvocationHandler.java | 8 +- .../intellij/util/xml/impl/InvocationCache.java | 10 +-- .../com/intellij/util/xml/DomReflectionUtil.java | 33 +++++--- dom/openapi/src/com/intellij/util/xml/DomUtil.java | 2 +- .../com/intellij/util/xml/JavaMethodSignature.java | 80 ++++++++++++------- openapi/src/com/intellij/psi/util/PsiTreeUtil.java | 7 +- .../reference/ReferenceProvidersRegistry.java | 3 +- util/src/com/intellij/util/ReflectionCache.java | 15 +++- 12 files changed, 220 insertions(+), 165 deletions(-) diff --git a/dom/impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java b/dom/impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java index 9a12855294..89f77edc38 100644 --- a/dom/impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java +++ b/dom/impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java @@ -19,6 +19,8 @@ import com.intellij.psi.xml.XmlTag; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ReflectionCache; +import com.intellij.util.containers.FactoryMap; import com.intellij.util.xml.*; import com.intellij.util.xml.events.CollectionElementAddedEvent; import com.intellij.util.xml.events.ElementDefinedEvent; @@ -26,6 +28,8 @@ import com.intellij.util.xml.events.ElementUndefinedEvent; import com.intellij.util.xml.reflect.DomAttributeChildDescription; import com.intellij.util.xml.reflect.DomChildrenDescription; import com.intellij.util.xml.reflect.DomFixedChildDescription; +import gnu.trove.THashMap; +import gnu.trove.THashSet; import net.sf.cglib.proxy.InvocationHandler; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -69,12 +73,12 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem private XmlFile myFile; private final DomElement myProxy; - private final Set myInitializedChildren = new com.intellij.util.containers.HashSet(); + private final Set myInitializedChildren = new THashSet(); private final Map, IndexedElementInvocationHandler> myFixedChildren = - new HashMap, IndexedElementInvocationHandler>(); - private final Map myAttributeChildren = new HashMap(); + new THashMap, IndexedElementInvocationHandler>(); + private final Map myAttributeChildren = new THashMap(); final private GenericInfoImpl myGenericInfo; - private final Map myFixedChildrenClasses = new HashMap(); + private final Map myFixedChildrenClasses = new THashMap(); private boolean myInvalidated; private InvocationCache myInvocationCache; private final Factory myGenericConverterFactory = new Factory() { @@ -82,6 +86,21 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem return myGenericConverter; } }; + private final FactoryMap myScalarConverters = new FactoryMap() { + protected Converter create(final Method method) { + final Type returnType = method.getGenericReturnType(); + final Type type = returnType == void.class ? method.getGenericParameterTypes()[0] : returnType; + final Class parameter = DomReflectionUtil.substituteGenericType(type, myType); + assert parameter != null : type + " " + myType; + final Converter converter = getConverter(new Function, Annotation>() { + public Annotation fun(final Class s) { + return DomReflectionUtil.findAnnotationDFS(method, s); + } + }, parameter, type instanceof TypeVariable ? myGenericConverterFactory : Factory.NULL_FACTORY); + assert converter != null : "No converter specified: String<->" + parameter.getName(); + return converter; + } + }; protected DomInvocationHandler(final Type type, final XmlTag tag, @@ -106,14 +125,13 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem myGenericConverter = converter; myInvocationCache = manager.getInvocationCache(new Pair(concreteInterface, converter == null ? null : converter.getClass())); - final Class rawType = DomReflectionUtil.getRawType(concreteInterface); + final Class rawType = getRawType(); Class implementation = manager.getImplementation(rawType); - if (implementation == null && !rawType.isInterface()) { + final boolean isInterface = ReflectionCache.isInterface(rawType); + if (implementation == null && !isInterface) { implementation = (Class)rawType; } - myProxy = rawType.isInterface() - ? AdvancedProxy.createProxy(this, implementation, rawType) - : AdvancedProxy.createProxy(this, implementation, ArrayUtil.EMPTY_CLASS_ARRAY); + myProxy = AdvancedProxy.createProxy(this, implementation, isInterface ? new Class[]{rawType} : ArrayUtil.EMPTY_CLASS_ARRAY); attach(tag); } @@ -193,7 +211,7 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem } public final T createMockCopy(final boolean physical) { - final T copy = myManager.createMockElement((Class)DomReflectionUtil.getRawType(myType), getModule(), physical); + final T copy = myManager.createMockElement((Class)getRawType(), getModule(), physical); copy.copyFrom(getProxy()); return copy; } @@ -369,16 +387,8 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem } @NotNull - protected final Converter getScalarConverter(final Type type, final Method method) { - final Class parameter = DomReflectionUtil.substituteGenericType(type, myType); - assert parameter != null : type + " " + myType; - final Converter converter = getConverter(new Function, Annotation>() { - public Annotation fun(final Class s) { - return DomReflectionUtil.findAnnotationDFS(method, s); - } - }, parameter, type instanceof TypeVariable ? myGenericConverterFactory : Factory.NULL_FACTORY); - assert converter != null : "No converter specified: String<->" + parameter.getName(); - return converter; + protected final Converter getScalarConverter(final Method method) { + return myScalarConverters.get(method); } @Nullable @@ -418,7 +428,7 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem } public final DomNameStrategy getNameStrategy() { - final Class rawType = DomReflectionUtil.getRawType(myType); + final Class rawType = getRawType(); final DomNameStrategy strategy = DomImplUtil.getDomNameStrategy(rawType, isAttribute()); if (strategy != null) { return strategy; @@ -465,11 +475,11 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem protected final Invocation createInvocation(final Method method) throws IllegalAccessException, InstantiationException { if (DomImplUtil.isTagValueGetter(method)) { - return createGetValueInvocation(getScalarConverter(method.getGenericReturnType(), method), method); + return createGetValueInvocation(getScalarConverter(method), method); } if (DomImplUtil.isTagValueSetter(method)) { - return createSetValueInvocation(getScalarConverter(method.getGenericParameterTypes()[0], method), method); + return createSetValueInvocation(getScalarConverter(method), method); } return myGenericInfo.createInvocation(method); @@ -524,7 +534,7 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem public final Object doInvoke(final JavaMethodSignature signature, final Object... args) throws Throwable { Invocation invocation = myInvocationCache.getInvocation(signature); if (invocation == null) { - invocation = createInvocation(signature.findMethod(DomReflectionUtil.getRawType(myType))); + invocation = createInvocation(signature.findMethod(getRawType())); myInvocationCache.putInvocation(signature, invocation); } return invocation.invoke(this, args); @@ -557,7 +567,7 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem if (ATTRIBUTES.equals(qname)) { for (Map.Entry entry : myGenericInfo.getAttributeChildrenEntries()) { - getOrCreateAttributeChild(entry.getKey().findMethod(DomReflectionUtil.getRawType(myType)), entry.getValue()); + getOrCreateAttributeChild(entry.getKey().findMethod(getRawType()), entry.getValue()); } } @@ -606,17 +616,27 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem } private IndexedElementInvocationHandler createIndexedChild(final XmlTag subTag, final Pair pair) { - final JavaMethodSignature signature = myGenericInfo.getFixedChildGetter(pair); final String qname = pair.getFirst(); - final Class rawType = DomReflectionUtil.getRawType(myType); - final Method method = signature.findMethod(rawType); - Type type = method.getGenericReturnType(); + final Type type = getIndexedChildType(qname, pair); + return new IndexedElementInvocationHandler(type, subTag, this, qname, pair.getSecond()); + } + + private Type getIndexedChildType(final String qname, final Pair pair) { + final Type type; if (myFixedChildrenClasses.containsKey(qname)) { type = getFixedChildrenClass(qname); } - final SubTag annotationDFS = signature.findAnnotation(SubTag.class, rawType); - final boolean indicator = annotationDFS != null && annotationDFS.indicator(); - return new IndexedElementInvocationHandler(type, subTag, this, qname, pair.getSecond(), indicator); + else { + final JavaMethodSignature signature = myGenericInfo.getFixedChildGetter(pair); + final Method method = signature.findMethod(getRawType()); + assert method != null; + type = method.getGenericReturnType(); + } + return type; + } + + protected final Class getRawType() { + return DomReflectionUtil.getRawType(myType); } protected final Class getFixedChildrenClass(final String tagName) { @@ -742,7 +762,7 @@ public abstract class DomInvocationHandler implements InvocationHandler, DomElem public void setFixedChildClass(final String tagName, final Class aClass) { synchronized (PsiLock.LOCK) { - assert!myInitializedChildren.contains(tagName); + assert !myInitializedChildren.contains(tagName); myFixedChildrenClasses.put(tagName, aClass); } } diff --git a/dom/impl/src/com/intellij/util/xml/impl/FixedChildDescriptionImpl.java b/dom/impl/src/com/intellij/util/xml/impl/FixedChildDescriptionImpl.java index e5a0d0e880..71d381af01 100644 --- a/dom/impl/src/com/intellij/util/xml/impl/FixedChildDescriptionImpl.java +++ b/dom/impl/src/com/intellij/util/xml/impl/FixedChildDescriptionImpl.java @@ -4,8 +4,8 @@ package com.intellij.util.xml.impl; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ArrayUtil; import com.intellij.util.xml.DomElement; import com.intellij.util.xml.DomNameStrategy; import com.intellij.util.xml.DomReflectionUtil; @@ -13,7 +13,6 @@ import com.intellij.util.xml.reflect.DomFixedChildDescription; import org.jetbrains.annotations.Nullable; import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.ArrayList; @@ -56,23 +55,7 @@ public class FixedChildDescriptionImpl extends DomChildDescriptionImpl implement final ArrayList result = new ArrayList(); for (Method method : myGetterMethods) { if (method != null) { - try { - //assert method.getDeclaringClass().isInstance(element) : method.getDeclaringClass() + " " + element.getClass(); - result.add((DomElement) method.invoke(element)); - } - catch (IllegalArgumentException e) { - LOG.error(e); - } - catch (IllegalAccessException e) { - LOG.error(e); - } - catch (InvocationTargetException e) { - final Throwable throwable = e.getCause(); - if (throwable instanceof ProcessCanceledException) { - throw (ProcessCanceledException)throwable; - } - LOG.error(e); - } + result.add((DomElement) DomReflectionUtil.invokeMethod(method, element, ArrayUtil.EMPTY_OBJECT_ARRAY)); } } return result; diff --git a/dom/impl/src/com/intellij/util/xml/impl/GenericInfoImpl.java b/dom/impl/src/com/intellij/util/xml/impl/GenericInfoImpl.java index a4c5fcf182..360fd721d8 100644 --- a/dom/impl/src/com/intellij/util/xml/impl/GenericInfoImpl.java +++ b/dom/impl/src/com/intellij/util/xml/impl/GenericInfoImpl.java @@ -12,10 +12,13 @@ import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.xml.XmlElement; import com.intellij.psi.xml.XmlTag; import com.intellij.util.Function; +import com.intellij.util.ReflectionCache; import com.intellij.util.containers.BidirectionalMap; import com.intellij.util.xml.*; import com.intellij.util.xml.reflect.DomChildrenDescription; import com.intellij.util.xml.reflect.DomGenericInfo; +import gnu.trove.THashSet; +import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,18 +37,18 @@ public class GenericInfoImpl implements DomGenericInfo { private DomManagerImpl myDomManager; private final BidirectionalMap> myFixedChildrenMethods = new BidirectionalMap>(); - private final Map myFixedChildrenCounts = new HashMap(); - private final Map myCollectionChildrenGetterMethods = new HashMap(); - private final Map myCollectionChildrenAdditionMethods = new HashMap(); - private final Map myCollectionChildrenClasses = new HashMap(); - private final Map myAttributeChildrenMethods = new HashMap(); - private final Map> myCompositeChildrenMethods = new HashMap>(); + private final Map myFixedChildrenCounts = new THashMap(); + private final Map myCollectionChildrenGetterMethods = new THashMap(); + private final Map myCollectionChildrenAdditionMethods = new THashMap(); + private final Map myCollectionChildrenClasses = new THashMap(); + private final Map myAttributeChildrenMethods = new THashMap(); + private final Map> myCompositeChildrenMethods = new THashMap>(); private final Map>> myCompositeCollectionAdditionMethods = - new HashMap>>(); + new THashMap>>(); @Nullable private Method myNameValueGetter; private boolean myValueElement; private boolean myInitialized; - private static final HashSet ADDER_PARAMETER_TYPES = new HashSet(Arrays.asList(Class.class, int.class)); + private static final Set ADDER_PARAMETER_TYPES = new THashSet(Arrays.asList(Class.class, int.class)); public GenericInfoImpl(final Class aClass, final DomManagerImpl domManager) { myClass = aClass; @@ -93,9 +96,11 @@ public class GenericInfoImpl implements DomGenericInfo { return myAttributeChildrenMethods.get(method); } - private static boolean isCoreMethod(final Method method) { + private static boolean isCoreMethod(final JavaMethodSignature signature, final Method method) { + if (signature.findMethod(DomElement.class) != null) return true; + final Class aClass = method.getDeclaringClass(); - return aClass.isAssignableFrom(DomElement.class) || aClass.equals(GenericAttributeValue.class); + return aClass.equals(GenericAttributeValue.class) || aClass.equals(GenericDomValue.class) && "getConverter".equals(method.getName()); } @Nullable @@ -143,76 +148,64 @@ public class GenericInfoImpl implements DomGenericInfo { myInitialized = true; - final Set methods = new HashSet(Arrays.asList(myClass.getMethods())); - final Set removedSignatures = new HashSet(); - - final Class implClass = myDomManager.getImplementation(myClass); - if (implClass != null) { - for (Method method : implClass.getMethods()) { - if (!Modifier.isAbstract(method.getModifiers())) { - removedSignatures.add(JavaMethodSignature.getSignature(method)); - } - } - for (Iterator iterator = methods.iterator(); iterator.hasNext();) { - final Method method = iterator.next(); - try { - if (!Modifier.isAbstract(implClass.getMethod(method.getName(), method.getParameterTypes()).getModifiers())) { - iterator.remove(); + final Map methods = new THashMap(); + for (final Method method : ReflectionCache.getMethods(myClass)) { + final JavaMethodSignature signature = JavaMethodSignature.getSignature(method); + methods.put(signature, signature.findMethod(myClass)); + } + { + final Class implClass = myDomManager.getImplementation(myClass); + if (implClass != null) { + final Set implemented = new THashSet(); + for (Method method : ReflectionCache.getMethods(implClass)) { + if (!Modifier.isAbstract(method.getModifiers())) { + implemented.add(JavaMethodSignature.getSignature(method)); } } - catch (NoSuchMethodException e) { + for (Iterator it = methods.keySet().iterator(); it.hasNext();) { + if (implemented.contains(it.next())) { + it.remove(); + } } } } - for (Iterator iterator = methods.iterator(); iterator.hasNext();) { - final Method method = iterator.next(); - - final JavaMethodSignature signature = JavaMethodSignature.getSignature(method); - final Required required = DomReflectionUtil.findAnnotationDFS(method, Required.class); - if (isCoreMethod(method) || DomImplUtil.isTagValueSetter(method) || isCustomMethod(signature)) { + for (Iterator iterator = methods.keySet().iterator(); iterator.hasNext();) { + final JavaMethodSignature signature = iterator.next(); + final Method method = methods.get(signature); + if (isCoreMethod(signature, method) || DomImplUtil.isTagValueSetter(method) || isCustomMethod(signature)) { if (signature.findAnnotation(NameValue.class, myClass) != null) { myNameValueGetter = method; } - removedSignatures.add(signature); iterator.remove(); } } - for (Iterator iterator = methods.iterator(); iterator.hasNext();) { - Method method = iterator.next(); + for (Iterator iterator = methods.keySet().iterator(); iterator.hasNext();) { + final JavaMethodSignature signature = iterator.next(); + final Method method = methods.get(signature); if (DomImplUtil.isGetter(method) && processGetterMethod(method)) { - final JavaMethodSignature signature = JavaMethodSignature.getSignature(method); if (signature.findAnnotation(NameValue.class, myClass) != null) { myNameValueGetter = method; } - removedSignatures.add(signature); iterator.remove(); } } - for (Iterator iterator = methods.iterator(); iterator.hasNext();) { - Method method = iterator.next(); - final JavaMethodSignature signature = JavaMethodSignature.getSignature(method); + for (Iterator iterator = methods.keySet().iterator(); iterator.hasNext();) { + final JavaMethodSignature signature = iterator.next(); + final Method method = methods.get(signature); final SubTagsList subTagsList = signature.findAnnotation(SubTagsList.class, myClass); if (subTagsList != null && method.getName().startsWith("add")) { final String tagName = subTagsList.tagName(); assert StringUtil.isNotEmpty(tagName); - final Set set = new HashSet(Arrays.asList(subTagsList.value())); + final Set set = new THashSet(Arrays.asList(subTagsList.value())); assert set.contains(tagName); myCompositeCollectionAdditionMethods.put(signature, Pair.create(tagName, set)); iterator.remove(); } else if (isAddMethod(method, signature)) { myCollectionChildrenAdditionMethods.put(signature, extractTagName(signature, "add")); - removedSignatures.add(JavaMethodSignature.getSignature(method)); - iterator.remove(); - } - } - for (Iterator iterator = methods.iterator(); iterator.hasNext();) { - Method method = iterator.next(); - final JavaMethodSignature signature = JavaMethodSignature.getSignature(method); - if (removedSignatures.contains(signature)) { iterator.remove(); } } @@ -220,7 +213,7 @@ public class GenericInfoImpl implements DomGenericInfo { if (false) { if (!methods.isEmpty()) { StringBuilder sb = new StringBuilder(myClass + " should provide the following implementations:"); - for (Method method : methods) { + for (Method method : methods.values()) { sb.append("\n " + method); } assert false : sb.toString(); diff --git a/dom/impl/src/com/intellij/util/xml/impl/GenericValueReferenceProvider.java b/dom/impl/src/com/intellij/util/xml/impl/GenericValueReferenceProvider.java index 9e27af2052..47b00353a2 100644 --- a/dom/impl/src/com/intellij/util/xml/impl/GenericValueReferenceProvider.java +++ b/dom/impl/src/com/intellij/util/xml/impl/GenericValueReferenceProvider.java @@ -16,10 +16,12 @@ import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.psi.xml.XmlElement; import com.intellij.psi.xml.XmlTag; import com.intellij.util.ArrayUtil; +import com.intellij.util.ReflectionCache; import com.intellij.util.xml.*; import com.intellij.util.xml.reflect.DomAttributeChildDescription; import org.jetbrains.annotations.NotNull; +import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -76,11 +78,11 @@ public class GenericValueReferenceProvider implements PsiReferenceProvider { } } - PsiReference[] references = createReferences(domValue, (XmlElement)psiElement, soft); + PsiReference[] references = createReferences(domValue, (XmlElement)psiElement, soft, converter); // creating "declaration" reference DomElement parent = domElement.getParent(); - if (domElement.equals(parent.getGenericInfo().getNameDomElement(parent)) && references.length == 0) { + if (references.length == 0) { final NameValue nameValue = domElement.getAnnotation(NameValue.class); if (nameValue != null && nameValue.referencable()) { references = ArrayUtil.append(references, PsiReferenceBase.createSelfReference(psiElement, parent.getXmlElement()), PsiReference.class); @@ -89,22 +91,25 @@ public class GenericValueReferenceProvider implements PsiReferenceProvider { return references; } - @NotNull - protected final PsiReference[] createReferences(GenericDomValue domValue, XmlElement psiElement, boolean soft) { + private static DomInvocationHandler getInvocationHandler(final GenericDomValue domValue) { + return DomManagerImpl.getDomInvocationHandler(domValue); + } - Converter converter = domValue.getConverter(); + @NotNull + protected final PsiReference[] createReferences(GenericDomValue domValue, XmlElement psiElement, boolean soft, final Converter converter) { if (converter instanceof PsiReferenceConverter) { return ((PsiReferenceConverter)converter).createReferences(psiElement, false); } - final Class clazz = DomUtil.getGenericValueParameter(domValue.getDomElementType()); + final DomInvocationHandler invocationHandler = getInvocationHandler(domValue); + final Class clazz = DomUtil.getGenericValueParameter(invocationHandler.getDomElementType()); if (clazz == null) return PsiReference.EMPTY_ARRAY; - if (PsiType.class.isAssignableFrom(clazz)) { + if (ReflectionCache.isAssignable(PsiType.class, clazz)) { return new PsiReference[]{new PsiTypeReference((GenericDomValue)domValue)}; } - if (PsiClass.class.isAssignableFrom(clazz)) { - ExtendClass extendClass = ((DomElement)domValue).getAnnotation(ExtendClass.class); + if (ReflectionCache.isAssignable(PsiClass.class, clazz)) { + ExtendClass extendClass = invocationHandler.getAnnotation(ExtendClass.class); JavaClassReferenceProvider provider; if (extendClass == null) { provider = new JavaClassReferenceProvider(); @@ -114,14 +119,14 @@ public class GenericValueReferenceProvider implements PsiReferenceProvider { } return provider.getReferencesByElement(psiElement); } - if (Integer.class.isAssignableFrom(clazz)) { + if (ReflectionCache.isAssignable(Integer.class, clazz)) { return new PsiReference[]{new GenericDomValueReference((GenericDomValue)domValue, true) { public Object[] getVariants() { return new Object[]{"239", "42"}; } }}; } - if (String.class.isAssignableFrom(clazz)) { + if (ReflectionCache.isAssignable(String.class, clazz)) { return PsiReference.EMPTY_ARRAY; } PsiReferenceFactory provider = myProviders.get(clazz); diff --git a/dom/impl/src/com/intellij/util/xml/impl/IndexedElementInvocationHandler.java b/dom/impl/src/com/intellij/util/xml/impl/IndexedElementInvocationHandler.java index 35b03bee9d..6f9b727f96 100644 --- a/dom/impl/src/com/intellij/util/xml/impl/IndexedElementInvocationHandler.java +++ b/dom/impl/src/com/intellij/util/xml/impl/IndexedElementInvocationHandler.java @@ -8,6 +8,7 @@ import com.intellij.openapi.util.Factory; import com.intellij.psi.xml.XmlTag; import com.intellij.util.IncorrectOperationException; import com.intellij.util.xml.DomElement; +import com.intellij.util.xml.SubTag; import com.intellij.util.xml.reflect.DomFixedChildDescription; import java.lang.annotation.Annotation; @@ -19,20 +20,19 @@ import java.lang.reflect.Type; public class IndexedElementInvocationHandler extends DomInvocationHandler{ private static final Logger LOG = Logger.getInstance("#com.intellij.util.xml.impl.IndexedElementInvocationHandler"); private final int myIndex; - private final boolean myIndicator; public IndexedElementInvocationHandler(final Type aClass, final XmlTag tag, final DomInvocationHandler parent, final String tagName, - final int index, final boolean indicator) { + final int index) { super(aClass, tag, parent, tagName, parent.getManager()); myIndex = index; - myIndicator = indicator; } final boolean isIndicator() { - return myIndicator; + final SubTag annotation = getAnnotation(SubTag.class); + return annotation != null && annotation.indicator(); } public final int getIndex() { diff --git a/dom/impl/src/com/intellij/util/xml/impl/InvocationCache.java b/dom/impl/src/com/intellij/util/xml/impl/InvocationCache.java index 41459b8f95..a9f6d644a5 100644 --- a/dom/impl/src/com/intellij/util/xml/impl/InvocationCache.java +++ b/dom/impl/src/com/intellij/util/xml/impl/InvocationCache.java @@ -3,15 +3,14 @@ */ package com.intellij.util.xml.impl; -import com.intellij.psi.xml.XmlTag; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.pom.Navigatable; import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlTag; import com.intellij.util.xml.*; import com.intellij.util.xml.ui.DomUIFactory; -import com.intellij.pom.Navigatable; -import com.intellij.openapi.progress.ProcessCanceledException; import java.lang.reflect.Method; -import java.lang.reflect.TypeVariable; import java.util.HashMap; import java.util.Map; @@ -45,11 +44,10 @@ public class InvocationCache { return null; } }); - final TypeVariable> typeVariable = GenericValue.class.getTypeParameters()[0]; ourCoreInvocations.put(JavaMethodSignature.getSignature(GenericDomValue.class.getMethod("getConverter")), new Invocation() { public final Object invoke(final DomInvocationHandler handler, final Object[] args) throws Throwable { try { - return handler.getScalarConverter(typeVariable, DomUIFactory.GET_VALUE_METHOD); + return handler.getScalarConverter(DomUIFactory.GET_VALUE_METHOD); } catch (Throwable e) { final Throwable cause = e.getCause(); diff --git a/dom/openapi/src/com/intellij/util/xml/DomReflectionUtil.java b/dom/openapi/src/com/intellij/util/xml/DomReflectionUtil.java index a1fec2d648..2ba002a31d 100644 --- a/dom/openapi/src/com/intellij/util/xml/DomReflectionUtil.java +++ b/dom/openapi/src/com/intellij/util/xml/DomReflectionUtil.java @@ -3,11 +3,11 @@ */ package com.intellij.util.xml; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ReflectionCache; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; import java.lang.annotation.Annotation; @@ -30,6 +30,9 @@ public class DomReflectionUtil { public static Object invokeMethod(final Method method, final Object object, final Object... args) { try { + //if (object instanceof Factory) { + // return ((net.sf.cglib.proxy.InvocationHandler)((Factory)object).getCallback(0)).invoke(object, method, args); + //} return method.invoke(object, args); } catch (IllegalArgumentException e) { @@ -51,6 +54,12 @@ public class DomReflectionUtil { } throw new RuntimeException(e); } + catch (ProcessCanceledException e) { + throw e; + } + catch (Throwable throwable) { + throw new RuntimeException(throwable); + } } public static Type resolveVariable(TypeVariable variable, final Class classType) { @@ -71,16 +80,18 @@ public class DomReflectionUtil { if (resolved instanceof TypeVariable) { final TypeVariable typeVariable = (TypeVariable)resolved; index = ContainerUtil.findByEquals(ReflectionCache.getTypeParameters(anInterface), typeVariable); - LOG.assertTrue(index >= 0, "Cannot resolve type variable:\n" + - "typeVariable = " + typeVariable + "\n" + - "genericDeclaration = " + declarationToString(typeVariable.getGenericDeclaration()) + "\n" + - "searching in " + declarationToString(anInterface)); + if (index < 0) { + LOG.assertTrue(false, "Cannot resolve type variable:\n" + + "typeVariable = " + typeVariable + "\n" + + "genericDeclaration = " + declarationToString(typeVariable.getGenericDeclaration()) + "\n" + + "searching in " + declarationToString(anInterface)); + } final Type type = genericInterfaces[i]; if (type instanceof Class) { return Object.class; } if (type instanceof ParameterizedType) { - return ((ParameterizedType)type).getActualTypeArguments()[index]; + return getActualTypeArguments(((ParameterizedType)type))[index]; } throw new AssertionError("Invalid type: " + type); } @@ -105,7 +116,7 @@ public class DomReflectionUtil { if (type instanceof TypeVariable && classType instanceof ParameterizedType) { final int index = ContainerUtil.findByEquals(ReflectionCache.getTypeParameters(aClass), type); if (index >= 0) { - return getRawType(((ParameterizedType)classType).getActualTypeArguments()[index]); + return getRawType(getActualTypeArguments(((ParameterizedType)classType))[index]); } } } else { @@ -150,7 +161,7 @@ public class DomReflectionUtil { if (rawType instanceof Class) { final Class rawClass = (Class)rawType; if (List.class.equals(rawClass) || Collection.class.equals(rawClass)) { - final Type[] arguments = parameterizedType.getActualTypeArguments(); + final Type[] arguments = getActualTypeArguments(parameterizedType); if (arguments.length == 1) { final Type argument = arguments[0]; if (argument instanceof WildcardType) { @@ -174,6 +185,10 @@ public class DomReflectionUtil { return null; } + private static Type[] getActualTypeArguments(final ParameterizedType parameterizedType) { + return ReflectionCache.getActualTypeArguments(parameterizedType); + } + public static boolean canHaveIsPropertyGetterPrefix(final Type type) { return boolean.class.equals(type) || Boolean.class.equals(type) || Boolean.class.equals(DomUtil.getGenericValueParameter(type)); diff --git a/dom/openapi/src/com/intellij/util/xml/DomUtil.java b/dom/openapi/src/com/intellij/util/xml/DomUtil.java index 07773713b1..2d4176f707 100644 --- a/dom/openapi/src/com/intellij/util/xml/DomUtil.java +++ b/dom/openapi/src/com/intellij/util/xml/DomUtil.java @@ -21,7 +21,7 @@ import java.util.*; * @author peter */ public class DomUtil { - private static final TypeVariable GENERIC_VALUE_TYPE_VARIABLE = ReflectionCache.getTypeParameters(GenericValue.class)[0]; + public static final TypeVariable> GENERIC_VALUE_TYPE_VARIABLE = ReflectionCache.getTypeParameters(GenericValue.class)[0]; private DomUtil() { } diff --git a/dom/openapi/src/com/intellij/util/xml/JavaMethodSignature.java b/dom/openapi/src/com/intellij/util/xml/JavaMethodSignature.java index f11876810e..83ee07c735 100644 --- a/dom/openapi/src/com/intellij/util/xml/JavaMethodSignature.java +++ b/dom/openapi/src/com/intellij/util/xml/JavaMethodSignature.java @@ -23,9 +23,9 @@ public class JavaMethodSignature { private static final Map, JavaMethodSignature> ourSignatures2 = new HashMap, JavaMethodSignature>(); private final String myMethodName; private final Class[] myMethodParameters; - private final Set myKnownClasses = new THashSet(); - private final List myAllMethods = new SmartList(); - private final Map myMethods = new THashMap(); + private final Set myKnownClasses = Collections.synchronizedSet(new THashSet()); + private final List myAllMethods = Collections.synchronizedList(new SmartList()); + private final Map myMethods = Collections.synchronizedMap(new THashMap()); private JavaMethodSignature(final String methodName, final Class[] methodParameters) { myMethodName = methodName; @@ -41,43 +41,64 @@ public class JavaMethodSignature { } public final Object invoke(final Object instance, final Object... args) throws IllegalAccessException, InvocationTargetException { - return findMethod(instance.getClass()).invoke(instance, args); + final Class aClass = instance.getClass(); + final Method method = findMethod(aClass); + assert method != null : "No method " + this + " in " + aClass; + return method.invoke(instance, args); } + @Nullable public final Method findMethod(final Class aClass) { - Method method = myMethods.get(aClass); - if (method == null) { - try { - method = aClass.getMethod(myMethodName, myMethodParameters); - } - catch (NoSuchMethodException e) { - throw new AssertionError(e); - } - myMethods.put(aClass, method); + if (myMethods.containsKey(aClass)) { + return myMethods.get(aClass); } + Method method = getDeclaredMethod(aClass); + if (method == null && ReflectionCache.isInterface(aClass)) { + method = getDeclaredMethod(Object.class); + } + myMethods.put(aClass, method); return method; } + private void addKnownMethod(Method method) { + final Class aClass = method.getDeclaringClass(); + if (!myKnownClasses.contains(aClass)) { + addMethodWithSupers(aClass, method); + } + } + private void addMethodsIfNeeded(final Class aClass) { if (!myKnownClasses.contains(aClass)) { - try { - myKnownClasses.add(aClass); - myAllMethods.add(aClass.getDeclaredMethod(myMethodName, myMethodParameters)); - } - catch (NoSuchMethodException e) { - } - final Class superClass = aClass.getSuperclass(); - if (superClass != null) { - addMethodsIfNeeded(superClass); - } else { - if (aClass.isInterface()) { - addMethodsIfNeeded(Object.class); - } - } - for (final Class anInterface : aClass.getInterfaces()) { - addMethodsIfNeeded(anInterface); + addMethodWithSupers(aClass, findMethod(aClass)); + } + } + + @Nullable + private Method getDeclaredMethod(final Class aClass) { + try { + return aClass.getMethod(myMethodName, myMethodParameters); + } + catch (NoSuchMethodException e) { + return null; + } + } + + private void addMethodWithSupers(final Class aClass, final Method method) { + myKnownClasses.add(aClass); + if (method != null) { + myAllMethods.add(method); + } + final Class superClass = aClass.getSuperclass(); + if (superClass != null) { + addMethodsIfNeeded(superClass); + } else { + if (aClass.isInterface()) { + addMethodsIfNeeded(Object.class); } } + for (final Class anInterface : aClass.getInterfaces()) { + addMethodsIfNeeded(anInterface); + } } @Nullable @@ -119,6 +140,7 @@ public class JavaMethodSignature { if (methodSignature == null) { ourSignatures.put(method, methodSignature = getSignature(method.getName(), method.getParameterTypes())); } + //methodSignature.addKnownMethod(method); } return methodSignature; } diff --git a/openapi/src/com/intellij/psi/util/PsiTreeUtil.java b/openapi/src/com/intellij/psi/util/PsiTreeUtil.java index 1c7f6dc1cc..fedba139b7 100644 --- a/openapi/src/com/intellij/psi/util/PsiTreeUtil.java +++ b/openapi/src/com/intellij/psi/util/PsiTreeUtil.java @@ -20,6 +20,9 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.search.PsiElementProcessor; +import com.intellij.psi.xml.XmlTag; +import com.intellij.psi.xml.XmlDocument; +import com.intellij.util.ReflectionCache; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -106,6 +109,8 @@ public class PsiTreeUtil { else if (aClass == PsiStatement.class) return child instanceof PsiStatement; else if (aClass == PsiCodeBlock.class) return child instanceof PsiCodeBlock; else if (aClass == PsiClassInitializer.class) return child instanceof PsiClassInitializer; + else if (aClass == XmlTag.class) return child instanceof XmlTag; + else if (aClass == XmlDocument.class) return child instanceof XmlDocument; return aClass.isInstance(child); } @@ -160,7 +165,7 @@ public class PsiTreeUtil { @Nullable public static T getParentOfType(@Nullable PsiElement element, @NotNull Class aClass, boolean strict) { - return getParentOfType(element, aClass, strict, !PsiDirectory.class.isAssignableFrom(aClass)); + return getParentOfType(element, aClass, strict, !ReflectionCache.isAssignable(PsiDirectory.class, aClass)); } @Nullable diff --git a/source/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java b/source/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java index 43cc5c4aa4..3cd9a94769 100644 --- a/source/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java +++ b/source/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java @@ -23,6 +23,7 @@ import com.intellij.psi.impl.source.resolve.reference.impl.providers.*; import com.intellij.psi.jsp.el.ELLiteralExpression; import com.intellij.psi.xml.*; import com.intellij.util.Function; +import com.intellij.util.ReflectionCache; import com.intellij.xml.util.HtmlReferenceProvider; import com.intellij.xml.util.XmlUtil; import org.jetbrains.annotations.NonNls; @@ -801,7 +802,7 @@ public class ReferenceProvidersRegistry implements ProjectComponent { private boolean isScopeFinal(Class scopeClass) { for (final Class aClass : myTempScopes) { - if (aClass.isAssignableFrom(scopeClass)) { + if (ReflectionCache.isAssignable(aClass, scopeClass)) { return false; } } diff --git a/util/src/com/intellij/util/ReflectionCache.java b/util/src/com/intellij/util/ReflectionCache.java index 61f6df568a..2783dc6d0d 100644 --- a/util/src/com/intellij/util/ReflectionCache.java +++ b/util/src/com/intellij/util/ReflectionCache.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull; import java.lang.reflect.Method; import java.lang.reflect.TypeVariable; import java.lang.reflect.Type; +import java.lang.reflect.ParameterizedType; import java.util.Map; import java.util.WeakHashMap; @@ -70,6 +71,12 @@ public class ReflectionCache { return key.getGenericInterfaces(); } }; + private static final WeakFactoryMap ourActualTypeArguments = new WeakFactoryMap() { + @NotNull + protected Type[] create(final ParameterizedType key) { + return key.getActualTypeArguments(); + } + }; public static Class getSuperClass(Class aClass) { Class superClass = ourSuperClasses.get(aClass); @@ -101,7 +108,7 @@ public class ReflectionCache { return ourIsInterfaces.get(aClass); } - public static TypeVariable[] getTypeParameters(Class aClass) { + public static TypeVariable>[] getTypeParameters(Class aClass) { return ourTypeParameters.get(aClass); } @@ -111,4 +118,10 @@ public class ReflectionCache { } } + public static Type[] getActualTypeArguments(ParameterizedType type) { + synchronized (ourActualTypeArguments) { + return ourActualTypeArguments.get(type); + } + } + } -- 2.11.4.GIT