From 975aa31856fdd4da0ecd3802f84644c0881b8ded Mon Sep 17 00:00:00 2001 From: "Irina.Chernushina" Date: Wed, 21 Mar 2018 14:09:38 +0100 Subject: [PATCH] vue: avoid recursion in getting tag's descriptor - reuse solution from angular, extract code into common place - in XmlTagImpl, use RecursionGuard because it is very likely to have such problems with some other tag & descriptor combinations EA-116625 - SOE: FlexMxmlNSDescriptor.getElementDescriptor --- .../impl/source/xml/XmlDescriptorUtil.java | 45 +++++++++++++++++++ .../psi/impl/source/xml/XmlTagImpl.java | 28 +++++------- 2 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlDescriptorUtil.java diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlDescriptorUtil.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlDescriptorUtil.java new file mode 100644 index 000000000000..203f0c8cf169 --- /dev/null +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlDescriptorUtil.java @@ -0,0 +1,45 @@ +// 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.psi.impl.source.xml; + +import com.intellij.html.impl.DelegatingRelaxedHtmlElementDescriptor; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlDocument; +import com.intellij.psi.xml.XmlTag; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.xml.XmlElementDescriptor; +import com.intellij.xml.XmlNSDescriptor; +import com.intellij.xml.XmlNSDescriptorEx; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.xml.XmlElementDescriptor.EMPTY_ARRAY; + +/** + * @author Irina.Chernushina on 3/21/2018. + */ +public class XmlDescriptorUtil { + public static XmlElementDescriptor[] getElementsDescriptors(XmlTag context) { + XmlDocumentImpl xmlDocument = PsiTreeUtil.getParentOfType(context, XmlDocumentImpl.class); + if (xmlDocument == null) return EMPTY_ARRAY; + return ContainerUtil.map2Array(xmlDocument.getRootTagNSDescriptor().getRootElementsDescriptors(xmlDocument), + XmlElementDescriptor.class, descriptor -> wrapInDelegating(descriptor)); + } + + public static XmlElementDescriptor getElementDescriptor(XmlTag childTag, XmlTag contextTag) { + final XmlDocument document = PsiTreeUtil.getParentOfType(contextTag, XmlDocument.class); + if (document == null) { + return null; + } + final XmlNSDescriptor nsDescriptor = document.getDefaultNSDescriptor(childTag.getNamespace(), true); + if (nsDescriptor instanceof XmlNSDescriptorEx) { + XmlElementDescriptor descriptor = ((XmlNSDescriptorEx)nsDescriptor).getElementDescriptor(childTag.getLocalName(), childTag.getNamespace()); + return descriptor != null ? wrapInDelegating(descriptor) : null; + } + return null; + } + + @NotNull + public static DelegatingRelaxedHtmlElementDescriptor wrapInDelegating(XmlElementDescriptor descriptor) { + return descriptor instanceof DelegatingRelaxedHtmlElementDescriptor ? (DelegatingRelaxedHtmlElementDescriptor)descriptor : + new DelegatingRelaxedHtmlElementDescriptor(descriptor); + } +} diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java index 3c530fc6299e..2a182d6f8ea4 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2013 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.psi.impl.source.xml; import com.intellij.javaee.ExternalResourceManager; @@ -494,9 +480,15 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag, HintedReferenc @Override public XmlElementDescriptor getDescriptor() { - return CachedValuesManager.getCachedValue(this, () -> - Result.create(computeElementDescriptor(), - PsiModificationTracker.MODIFICATION_COUNT, externalResourceModificationTracker())); + return CachedValuesManager.getCachedValue(this, () -> { + final RecursionGuard.StackStamp stamp = ourGuard.markStack(); + final XmlElementDescriptor descriptor = ourGuard.doPreventingRecursion(this, true, this::computeElementDescriptor); + if (stamp.mayCacheNow()) { + return Result.create(descriptor, PsiModificationTracker.MODIFICATION_COUNT, externalResourceModificationTracker()); + } + // = do not cache + return Result.create(descriptor, ModificationTracker.EVER_CHANGED); + }); } private ModificationTracker externalResourceModificationTracker() {