diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomFileElementImpl.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomFileElementImpl.java index 6f7e6613bb52..8accda5c5999 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomFileElementImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomFileElementImpl.java @@ -15,17 +15,18 @@ */ package com.intellij.util.xml.impl; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiManager; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlElement; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; +import com.intellij.semantic.SemElement; import com.intellij.util.ObjectUtils; import com.intellij.util.xml.*; import com.intellij.util.xml.reflect.*; @@ -45,8 +46,7 @@ import java.util.Map; /** * @author peter */ -public class DomFileElementImpl implements DomFileElement { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.xml.impl.DomFileElementImpl"); +public class DomFileElementImpl implements DomFileElement, SemElement { private static final DomGenericInfo EMPTY_DOM_GENERIC_INFO = new DomGenericInfo() { @Override @@ -141,17 +141,13 @@ public class DomFileElementImpl implements DomFileElement< private final DomManagerImpl myManager; private final Map myUserData = new HashMap<>(); - protected DomFileElementImpl(final XmlFile file, - final Class rootElementClass, - final EvaluatedXmlNameImpl rootTagName, - final DomManagerImpl manager, final DomFileDescription fileDescription, - FileStub stub) { + protected DomFileElementImpl(XmlFile file, EvaluatedXmlNameImpl rootTagName, DomFileDescription fileDescription, FileStub stub) { myFile = file; - myRootElementClass = rootElementClass; + myRootElementClass = fileDescription.getRootElementClass(); myRootTagName = rootTagName; - myManager = manager; + myManager = DomManagerImpl.getDomManager(file.getProject()); myFileDescription = fileDescription; - myRootHandler = new DomRootInvocationHandler(rootElementClass, new RootDomParentStrategy(this), this, rootTagName, + myRootHandler = new DomRootInvocationHandler(myRootElementClass, new RootDomParentStrategy(this), this, rootTagName, stub == null ? null : stub.getRootTagStub()); } @@ -304,18 +300,8 @@ public class DomFileElementImpl implements DomFileElement< @NotNull public final T getRootElement() { if (!isValid()) { - if (!myFile.isValid()) { - assert false: myFile + " is not valid"; - } else { - final DomFileElementImpl fileElement = myManager.getFileElement(myFile); - if (fileElement == null) { - final FileDescriptionCachedValueProvider provider = myManager.getOrCreateCachedValueProvider(myFile); - String s = provider.getFileElementWithLogging(); - LOG.error("Null, log=" + s); - } else { - assert false: this + " does not equal to " + fileElement; - } - } + PsiUtilCore.ensureValid(myFile); + throw new AssertionError(this + " is not equal to " + myManager.getFileElement(myFile)); } return (T)getRootHandler().getProxy(); } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java index 094be024c7b8..01d446dbd1fe 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java @@ -61,7 +61,7 @@ public final class DomManagerImpl extends DomManager { static final Key> CACHED_FILE_ELEMENT = Key.create("CACHED_FILE_ELEMENT"); static final Key MOCK_DESCRIPTION = Key.create("MockDescription"); - static final SemKey FILE_DESCRIPTION_KEY = SemKey.createKey("FILE_DESCRIPTION_KEY"); + static final SemKey FILE_ELEMENT_KEY = SemKey.createKey("FILE_ELEMENT_KEY"); static final SemKey DOM_HANDLER_KEY = SemKey.createKey("DOM_HANDLER_KEY"); static final SemKey DOM_INDEXED_HANDLER_KEY = DOM_HANDLER_KEY.subKey("DOM_INDEXED_HANDLER_KEY"); static final SemKey DOM_COLLECTION_HANDLER_KEY = DOM_HANDLER_KEY.subKey("DOM_COLLECTION_HANDLER_KEY"); @@ -271,14 +271,6 @@ public final class DomManagerImpl extends DomManager { return fileElement; } - - @SuppressWarnings({"unchecked"}) - @NotNull - final FileDescriptionCachedValueProvider getOrCreateCachedValueProvider(@NotNull XmlFile xmlFile) { - //noinspection ConstantConditions - return mySemService.getSemElement(FILE_DESCRIPTION_KEY, xmlFile); - } - public final Set getFileDescriptions(String rootTagName) { return myApplicationComponent.getFileDescriptions(rootTagName); } @@ -315,11 +307,9 @@ public final class DomManagerImpl extends DomManager { @Override @Nullable public final DomFileElementImpl getFileElement(@Nullable XmlFile file) { - if (file == null) return null; - if (!(file.getFileType() instanceof DomSupportEnabled)) return null; - final VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile != null && virtualFile.isDirectory()) return null; - return this.getOrCreateCachedValueProvider(file).getFileElement(); + if (file == null || !(file.getFileType() instanceof DomSupportEnabled)) return null; + //noinspection unchecked + return mySemService.getSemElement(FILE_ELEMENT_KEY, file); } @Nullable diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomSemContributor.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomSemContributor.java index 1ae101cf87e9..dab280f2cbfe 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomSemContributor.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomSemContributor.java @@ -1,13 +1,22 @@ // Copyright 2000-2019 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.util.xml.impl; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.ide.highlighter.DomSupportEnabled; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectCoreUtil; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.RecursionManager; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.patterns.ElementPattern; import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.PsiFileEx; +import com.intellij.psi.stubs.ObjectStubTree; +import com.intellij.psi.stubs.StubTreeLoader; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlElementType; import com.intellij.psi.xml.XmlFile; @@ -16,18 +25,20 @@ import com.intellij.semantic.SemContributor; import com.intellij.semantic.SemRegistrar; import com.intellij.semantic.SemService; import com.intellij.util.ArrayUtil; -import com.intellij.util.xml.EvaluatedXmlName; -import com.intellij.util.xml.EvaluatedXmlNameImpl; -import com.intellij.util.xml.XmlName; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.indexing.FileBasedIndex; +import com.intellij.util.xml.*; import com.intellij.util.xml.reflect.CustomDomChildrenDescription; import com.intellij.util.xml.reflect.DomChildrenDescription; import com.intellij.util.xml.reflect.DomCollectionChildDescription; import com.intellij.util.xml.reflect.DomFixedChildDescription; import com.intellij.util.xml.stubs.DomStub; import com.intellij.util.xml.stubs.ElementStub; +import com.intellij.util.xml.stubs.FileStub; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.ref.WeakReference; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; @@ -42,18 +53,12 @@ import static com.intellij.patterns.XmlPatterns.*; final class DomSemContributor extends SemContributor { @Override public void registerSemProviders(@NotNull SemRegistrar registrar, @NotNull Project project) { - registrar.registerSemElementProvider(DomManagerImpl.FILE_DESCRIPTION_KEY, xmlFile(), xmlFile -> { - ApplicationManager.getApplication().assertReadAccessAllowed(); - return new FileDescriptionCachedValueProvider(DomManagerImpl.getDomManager(xmlFile.getProject()), xmlFile); - }); + registrar.registerSemElementProvider(DomManagerImpl.FILE_ELEMENT_KEY, xmlFile(), DomSemContributor::createFileElement); final SemService semService = SemService.getSemService(project); registrar.registerSemElementProvider(DomManagerImpl.DOM_HANDLER_KEY, xmlTag().withParent(psiElement(XmlElementType.XML_DOCUMENT).withParent(xmlFile())), xmlTag -> { - final FileDescriptionCachedValueProvider provider = - semService.getSemElement(DomManagerImpl.FILE_DESCRIPTION_KEY, xmlTag.getContainingFile()); - assert provider != null; - final DomFileElementImpl element = provider.getFileElement(); + DomFileElementImpl element = semService.getSemElement(DomManagerImpl.FILE_ELEMENT_KEY, xmlTag.getContainingFile()); if (element != null) { final DomRootInvocationHandler handler = element.getRootHandler(); if (handler.getXmlTag() == xmlTag) { @@ -169,6 +174,63 @@ final class DomSemContributor extends SemContributor { DomSemContributor::createAttributeHandler); } + @Nullable + private static DomFileElementImpl createFileElement(XmlFile xmlFile) { + VirtualFile file = xmlFile.getVirtualFile(); + if (!(xmlFile.getFileType() instanceof DomSupportEnabled) || file != null && ProjectCoreUtil.isProjectOrWorkspaceFile(file)) { + return null; + } + + DomFileDescription description = findFileDescription(xmlFile); + if (description == null) { + return null; + } + + XmlName xmlName = DomImplUtil.createXmlName(description.getRootTagName(), description.getRootElementClass(), null); + assert xmlName != null; + EvaluatedXmlNameImpl rootTagName1 = EvaluatedXmlNameImpl.createEvaluatedXmlName(xmlName, xmlName.getNamespaceKey(), false); + + FileStub stub = null; + DomFileMetaData meta = DomApplicationComponent.getInstance().findMeta(description); + if (meta != null && meta.hasStubs() && file instanceof VirtualFileWithId && !isFileParsed(xmlFile)) { + if (FileBasedIndex.getInstance().getFileBeingCurrentlyIndexed() == null) { + ObjectStubTree stubTree = StubTreeLoader.getInstance().readFromVFile(xmlFile.getProject(), file); + if (stubTree != null) { + stub = (FileStub)stubTree.getRoot(); + } + } + } + + //noinspection unchecked + DomFileElementImpl element = new DomFileElementImpl(xmlFile, rootTagName1, description, stub); + xmlFile.putUserData(DomManagerImpl.CACHED_FILE_ELEMENT, new WeakReference<>(element)); + return element; + } + + private static boolean isFileParsed(XmlFile myXmlFile) { + return myXmlFile instanceof PsiFileEx && ((PsiFileEx)myXmlFile).isContentsLoaded(); + } + + @Nullable + private static DomFileDescription findFileDescription(XmlFile file) { + DomFileDescription mockDescription = file.getUserData(DomManagerImpl.MOCK_DESCRIPTION); + if (mockDescription != null) return mockDescription; + + Project project = file.getProject(); + XmlFile originalFile = (XmlFile)file.getOriginalFile(); + if (!originalFile.equals(file)) { + DomFileElementImpl element = SemService.getSemService(project).getSemElement(DomManagerImpl.FILE_ELEMENT_KEY, originalFile); + return element == null ? null : element.getFileDescription(); + } + + DomManagerImpl domManager = DomManagerImpl.getDomManager(project); + Module module = ModuleUtilCore.findModuleForFile(file); + Condition condition = d -> d.isMyFile(file, module); + String rootTagLocalName = DomService.getInstance().getXmlFileHeader(file).getRootTagLocalName(); + DomFileDescription description = ContainerUtil.find(domManager.getFileDescriptions(rootTagLocalName), condition); + return description != null ? description : ContainerUtil.find(domManager.getAcceptingOtherRootTagNameDescriptions(), condition); + } + @Nullable static DomInvocationHandler getParentDom(@NotNull XmlTag tag) { LinkedHashSet allParents = new LinkedHashSet<>(); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java b/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java deleted file mode 100644 index d3aaf74131eb..000000000000 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 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. - */ -package com.intellij.util.xml.impl; - -import com.intellij.ide.highlighter.DomSupportEnabled; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.ProjectCoreUtil; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileWithId; -import com.intellij.psi.impl.PsiFileEx; -import com.intellij.psi.stubs.ObjectStubTree; -import com.intellij.psi.stubs.StubTreeLoader; -import com.intellij.psi.xml.XmlFile; -import com.intellij.semantic.SemElement; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.indexing.FileBasedIndex; -import com.intellij.util.xml.*; -import com.intellij.util.xml.stubs.FileStub; -import org.jetbrains.annotations.Nullable; - -import java.lang.ref.WeakReference; -import java.util.HashSet; -import java.util.Set; - -/** - * @author peter - */ -@SuppressWarnings({"HardCodedStringLiteral", "StringConcatenationInsideStringBufferAppend"}) -class FileDescriptionCachedValueProvider implements SemElement{ - - private final XmlFile myXmlFile; - private volatile boolean myComputed; - private volatile DomFileElementImpl myLastResult; - private final MyCondition myCondition = new MyCondition(); - - private final DomManagerImpl myDomManager; - private final DomService myDomService; - - FileDescriptionCachedValueProvider(final DomManagerImpl domManager, final XmlFile xmlFile) { - myDomManager = domManager; - myXmlFile = xmlFile; - myDomService = DomService.getInstance(); - } - - @Nullable - public final DomFileElementImpl getFileElement() { - if (myComputed) return myLastResult; - - DomFileElementImpl result = _computeFileElement(null); - - synchronized (myCondition) { - if (myComputed) return myLastResult; - - myLastResult = result; - WeakReference ref = result != null ? new WeakReference<>(result) : null; - myXmlFile.putUserData(DomManagerImpl.CACHED_FILE_ELEMENT, ref); - myComputed = true; - return result; - } - } - - @Nullable - private DomFileElementImpl _computeFileElement(@Nullable StringBuilder sb) { - if (!myXmlFile.isValid()) { - return null; - } - if (sb != null) { - sb.append("File is valid\n"); - } - - VirtualFile file = myXmlFile.getVirtualFile(); - if (!(myXmlFile.getFileType() instanceof DomSupportEnabled) || file != null && ProjectCoreUtil.isProjectOrWorkspaceFile(file)) { - return null; - } - - XmlFileHeader rootTagName = myDomService.getXmlFileHeader(myXmlFile); - if (sb != null) { - sb.append(rootTagName).append(", file is of dom file type\n"); - } - - final DomFileDescription description = findFileDescription(rootTagName, sb); - - final DomFileElementImpl oldValue = getLastValue(); - if (sb != null) { - sb.append("last " + oldValue + "\n"); - } - - if (description == null) { - return null; - } - - final Class rootElementClass = description.getRootElementClass(); - final XmlName xmlName = DomImplUtil.createXmlName(description.getRootTagName(), rootElementClass, null); - assert xmlName != null; - final EvaluatedXmlNameImpl rootTagName1 = EvaluatedXmlNameImpl.createEvaluatedXmlName(xmlName, xmlName.getNamespaceKey(), false); - - FileStub stub = null; - DomFileMetaData meta = DomApplicationComponent.getInstance().findMeta(description); - if (meta != null && meta.hasStubs() && file instanceof VirtualFileWithId && !isFileParsed()) { - ApplicationManager.getApplication().assertReadAccessAllowed(); - if (FileBasedIndex.getInstance().getFileBeingCurrentlyIndexed() == null) { - ObjectStubTree stubTree = StubTreeLoader.getInstance().readFromVFile(myXmlFile.getProject(), file); - if (stubTree != null) { - stub = (FileStub)stubTree.getRoot(); - } - } - } - - DomFileElementImpl result = new DomFileElementImpl<>(myXmlFile, rootElementClass, rootTagName1, myDomManager, description, stub); - if (sb != null) { - sb.append("success " + result + "\n"); - } - - return result; - } - - private boolean isFileParsed() { - return myXmlFile instanceof PsiFileEx && ((PsiFileEx)myXmlFile).isContentsLoaded(); - } - - @Nullable - private DomFileDescription findFileDescription(final XmlFileHeader xmlFileHeader, @Nullable StringBuilder sb) { - //noinspection unchecked - final DomFileDescription mockDescription = myXmlFile.getUserData(DomManagerImpl.MOCK_DESCRIPTION); - if (mockDescription != null) return mockDescription; - - if (sb != null) { - sb.append("no mock\n"); - } - - final XmlFile originalFile = (XmlFile)myXmlFile.getOriginalFile(); - if (sb != null) { - sb.append("original: " + originalFile + "\n"); - } - if (!originalFile.equals(myXmlFile)) { - final FileDescriptionCachedValueProvider provider = myDomManager.getOrCreateCachedValueProvider(originalFile); - final DomFileElementImpl element = provider.getFileElement(); - if (sb != null) { - sb.append("originalDom " + element + "\n"); - } - return element == null ? null : element.getFileDescription(); - } - - final Set namedDescriptions = myDomManager.getFileDescriptions(xmlFileHeader.getRootTagLocalName()); - if (sb != null) { - sb.append("named " + new HashSet<>(namedDescriptions) + "\n"); - } - //noinspection unchecked - DomFileDescription description = ContainerUtil.find(namedDescriptions, myCondition); - if (description == null) { - final Set unnamed = myDomManager.getAcceptingOtherRootTagNameDescriptions(); - //noinspection unchecked - description = ContainerUtil.find(unnamed, myCondition); - } - if (sb != null) { - sb.append("found " + description + "\n"); - } - return description; - } - - @Nullable - final DomFileElementImpl getLastValue() { - return myLastResult; - } - - public String getFileElementWithLogging() { - StringBuilder log = new StringBuilder(); - myLastResult = _computeFileElement(log); - return log.toString(); - } - - private class MyCondition implements Condition { - public Module module; - - @Override - public boolean value(final DomFileDescription description) { - return description.isMyFile(myXmlFile, module); - } - } - -}