From 4a1d5a5c445a3922265f14367ad4c86bfde45d4d Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Fri, 19 Jan 2018 19:22:18 +0300 Subject: [PATCH] IDEA-185183 Performance degradation in tests on 181 branch further optimization - call parent.getChildren() only once for 'large' parents --- .../impl/JavaElementSignatureProvider.java | 28 +++++++------------ .../AbstractElementSignatureProvider.java | 19 ++++++++++++- .../PsiNamesElementSignatureProvider.java | 11 ++------ .../impl/XmlElementSignatureProvider.java | 20 +++---------- 4 files changed, 35 insertions(+), 43 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaElementSignatureProvider.java b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaElementSignatureProvider.java index 9262f8a4d24b..1b766ccde863 100644 --- a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaElementSignatureProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaElementSignatureProvider.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInsight.folding.impl; import com.intellij.openapi.diagnostic.Logger; @@ -53,7 +39,9 @@ public class JavaElementSignatureProvider extends AbstractElementSignatureProvid String name = method.getName(); buffer.append(name); buffer.append(ELEMENT_TOKENS_SEPARATOR); - buffer.append(getChildIndex(method, parent, name, PsiMethod.class)); + int childIndex = getChildIndex(method, parent, name, PsiMethod.class); + if (childIndex < 0) return null; + buffer.append(childIndex); if (parent instanceof PsiClass) { String parentSignature = getSignature(parent); @@ -74,7 +62,9 @@ public class JavaElementSignatureProvider extends AbstractElementSignatureProvid String name = aClass.getName(); buffer.append(name); buffer.append(ELEMENT_TOKENS_SEPARATOR); - buffer.append(getChildIndex(aClass, parent, name, PsiClass.class)); + int childIndex = getChildIndex(aClass, parent, name, PsiClass.class); + if (childIndex < 0) return null; + buffer.append(childIndex); if (parent instanceof PsiClass) { String parentSignature = getSignature(parent); @@ -128,7 +118,9 @@ public class JavaElementSignatureProvider extends AbstractElementSignatureProvid buffer.append(name); buffer.append(ELEMENT_TOKENS_SEPARATOR); - buffer.append(getChildIndex(field, parent, name, PsiField.class)); + int childIndex = getChildIndex(field, parent, name, PsiField.class); + if (childIndex < 0) return null; + buffer.append(childIndex); if (parent instanceof PsiClass) { String parentSignature = getSignature(parent); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/AbstractElementSignatureProvider.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/AbstractElementSignatureProvider.java index 78188e0c878a..5b6a41a1df1c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/AbstractElementSignatureProvider.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/AbstractElementSignatureProvider.java @@ -1,4 +1,4 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInsight.folding.impl; import com.intellij.openapi.util.Comparing; @@ -6,12 +6,16 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; import com.intellij.util.ReflectionUtil; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.StringTokenizer; /** @@ -19,6 +23,7 @@ import java.util.StringTokenizer; * @since 11/7/11 12:00 PM */ public abstract class AbstractElementSignatureProvider implements ElementSignatureProvider { + private static final int CHILDREN_COUNT_LIMIT = 100; static final String ELEMENTS_SEPARATOR = ";"; static final String ELEMENT_TOKENS_SEPARATOR = "#"; @@ -69,8 +74,20 @@ public abstract class AbstractElementSignatureProvider implements ElementSignatu @NotNull StringTokenizer tokenizer, @Nullable StringBuilder processingInfoStorage); + /** + * @return -1, if {@code parent} has too many children and calculating child index would be too slow + */ protected static int getChildIndex(T element, PsiElement parent, String name, Class hisClass) { + PsiFile file = parent.getContainingFile(); + Set cache = file == null ? null : + CachedValuesManager.getCachedValue(file, () -> new CachedValueProvider.Result<>(ContainerUtil.createWeakSet(), file)); + if (cache != null && cache.contains(parent)) return -1; PsiElement[] children = parent.getChildren(); + if (children.length > CHILDREN_COUNT_LIMIT) { + if (cache != null) cache.add(parent); + return -1; + } + int index = 0; for (PsiElement child : children) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java index f079ee365ece..bd63ee6f81c9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java @@ -1,6 +1,4 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInsight.folding.impl; import com.intellij.openapi.util.text.StringUtil; @@ -21,8 +19,7 @@ import java.util.StringTokenizer; * @since 11/7/11 11:58 AM */ public class PsiNamesElementSignatureProvider extends AbstractElementSignatureProvider { - private static final int CHILDREN_COUNT_LIMIT = 100; - + private static final String TYPE_MARKER = "n"; private static final String TOP_LEVEL_CHILD_MARKER = "!!top"; private static final String DOC_COMMENT_MARKER = "!!doc"; @@ -178,14 +175,12 @@ public class PsiNamesElementSignatureProvider extends AbstractElementSignaturePr @Nullable private static StringBuilder getSignature(@NotNull PsiElement element, @Nullable StringBuilder buffer) { if (element instanceof PsiNamedElement) { - PsiElement parent = element.getParent(); - if (parent.getChildren().length > CHILDREN_COUNT_LIMIT) return null; // for performance reasons PsiNamedElement named = (PsiNamedElement)element; final String name = named.getName(); if (StringUtil.isEmpty(name)) { return null; } - int index = getChildIndex(named, parent, name, PsiNamedElement.class); + int index = getChildIndex(named, element.getParent(), name, PsiNamedElement.class); StringBuilder bufferToUse = buffer; if (bufferToUse == null) { bufferToUse = new StringBuilder(); diff --git a/xml/impl/src/com/intellij/codeInsight/folding/impl/XmlElementSignatureProvider.java b/xml/impl/src/com/intellij/codeInsight/folding/impl/XmlElementSignatureProvider.java index 8a51c340f825..b9d60b2d152f 100644 --- a/xml/impl/src/com/intellij/codeInsight/folding/impl/XmlElementSignatureProvider.java +++ b/xml/impl/src/com/intellij/codeInsight/folding/impl/XmlElementSignatureProvider.java @@ -1,18 +1,4 @@ -/* - * 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInsight.folding.impl; import com.intellij.openapi.diagnostic.Logger; @@ -46,7 +32,9 @@ public class XmlElementSignatureProvider extends AbstractElementSignatureProvide buffer.append(name.length() == 0 ? "" : escape(name)); buffer.append(ELEMENT_TOKENS_SEPARATOR); - buffer.append(getChildIndex(tag, parent, name, XmlTag.class)); + int childIndex = getChildIndex(tag, parent, name, XmlTag.class); + if (childIndex < 0) return null; + buffer.append(childIndex); if (!(parent instanceof PsiFile)) { String parentSignature = getSignature(parent);