From 57f9fd0d05dc2bef2b07810ec5fbd3562917e547 Mon Sep 17 00:00:00 2001 From: Piotr Tomiak Date: Tue, 1 Oct 2019 10:34:56 +0200 Subject: [PATCH] Xml: introduce stub based tags - XML tag stub fully supported GitOrigin-RevId: 47dd7b9b22f0e7a5674e011835c1e06dd749f21b --- .../lang/xpath/xslt/util/NSDeclTracker.java | 5 +- .../xml/XmlWhiteSpaceFormattingStrategy.java | 4 +- .../GotoXmlSchemaTypeRendererProvider.java | 14 +- .../impl/schema/SchemaDefinitionsSearch.java | 28 ++-- .../src/com/intellij/psi/xml/XmlTag.java | 4 + .../lang/html/HTMLParserDefinition.java | 7 +- .../lang/xml/XMLParserDefinition.java | 5 + .../html/HtmlStubBasedTagElementType.java | 54 ++++++++ .../source/html/HtmlStubBasedTagImpl.java | 130 ++++++++++++++++++ .../source/parsing/xml/XmlBuilderDriver.java | 7 +- .../impl/source/xml/XmlStubBasedElement.java | 23 +++- .../impl/source/xml/XmlStubBasedTagBase.java | 8 +- .../psi/impl/source/xml/XmlTagDelegate.java | 8 +- .../psi/impl/source/xml/XmlTagImpl.java | 9 -- .../psi/impl/source/xml/XmlTagValueImpl.java | 2 +- .../source/xml/stub/XmlAttributeStubImpl.java | 4 +- .../XmlStubBasedAttributeElementType.java | 29 +--- .../xml/stub/XmlStubBasedElementType.java | 46 +++++++ .../xml/stub/XmlStubBasedTagElementType.java | 30 +--- .../impl/source/xml/stub/XmlTagStubImpl.java | 6 +- .../intellij/psi/xml/IXmlTagElementType.java | 5 + .../com/intellij/psi/xml/XmlElementType.java | 15 +- .../src/com/intellij/xml/util/HtmlUtil.java | 3 +- .../documentation/HtmlCompatibilityData.java | 7 +- 24 files changed, 337 insertions(+), 116 deletions(-) create mode 100644 xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/HtmlStubBasedTagElementType.java create mode 100644 xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/HtmlStubBasedTagImpl.java create mode 100644 xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedElementType.java create mode 100644 xml/xml-psi-impl/src/com/intellij/psi/xml/IXmlTagElementType.java diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/util/NSDeclTracker.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/util/NSDeclTracker.java index 5930c703a59d..326f39d97cdc 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/util/NSDeclTracker.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/util/NSDeclTracker.java @@ -18,7 +18,6 @@ package org.intellij.lang.xpath.xslt.util; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.ModificationTracker; import com.intellij.psi.PsiFile; -import com.intellij.psi.impl.source.xml.XmlTagImpl; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; @@ -30,14 +29,14 @@ import java.util.List; public class NSDeclTracker implements ModificationTracker { private static final Key MOD_COUNT = Key.create("MOD_COUNT"); - private final XmlTagImpl myRootTag; + private final XmlTag myRootTag; private final PsiFile myFile; private final List myNSDecls; private long myRootCount; private int myCount; public NSDeclTracker(XmlTag rootTag) { - myRootTag = (XmlTagImpl)rootTag; + myRootTag = rootTag; myFile = rootTag.getContainingFile(); myNSDecls = getNSDecls(false); myRootCount = myFile.getModificationStamp(); diff --git a/xml/impl/src/com/intellij/lang/xml/XmlWhiteSpaceFormattingStrategy.java b/xml/impl/src/com/intellij/lang/xml/XmlWhiteSpaceFormattingStrategy.java index 043335603705..686d2fd674fb 100644 --- a/xml/impl/src/com/intellij/lang/xml/XmlWhiteSpaceFormattingStrategy.java +++ b/xml/impl/src/com/intellij/lang/xml/XmlWhiteSpaceFormattingStrategy.java @@ -23,6 +23,7 @@ import com.intellij.psi.impl.source.tree.Factory; import com.intellij.psi.impl.source.tree.LeafElement; import com.intellij.psi.impl.source.tree.SharedImplUtil; import com.intellij.psi.impl.source.tree.TreeElement; +import com.intellij.psi.xml.IXmlTagElementType; import com.intellij.psi.xml.XmlElementType; import com.intellij.psi.xml.XmlText; import com.intellij.psi.xml.XmlTokenType; @@ -68,8 +69,7 @@ public class XmlWhiteSpaceFormattingStrategy extends WhiteSpaceFormattingStrateg protected boolean isInsideTagBody(@NotNull ASTNode place) { final ASTNode treeParent = place.getTreeParent(); - if(treeParent.getElementType() != XmlElementType.XML_TAG - && treeParent.getElementType() != XmlElementType.HTML_TAG) return false; + if (!(treeParent.getElementType() instanceof IXmlTagElementType)) return false; while(place != null){ if(place.getElementType() == XmlTokenType.XML_TAG_END) return true; place = place.getTreePrev(); diff --git a/xml/impl/src/com/intellij/xml/impl/schema/GotoXmlSchemaTypeRendererProvider.java b/xml/impl/src/com/intellij/xml/impl/schema/GotoXmlSchemaTypeRendererProvider.java index 3800303e6898..67c2d4e9fa93 100644 --- a/xml/impl/src/com/intellij/xml/impl/schema/GotoXmlSchemaTypeRendererProvider.java +++ b/xml/impl/src/com/intellij/xml/impl/schema/GotoXmlSchemaTypeRendererProvider.java @@ -20,24 +20,24 @@ import com.intellij.codeInsight.navigation.GotoTargetRendererProvider; import com.intellij.ide.util.PsiElementListCellRenderer; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.impl.source.xml.XmlTagImpl; import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlTag; import org.jetbrains.annotations.NotNull; public class GotoXmlSchemaTypeRendererProvider implements GotoTargetRendererProvider { @Override public PsiElementListCellRenderer getRenderer(@NotNull PsiElement element, @NotNull GotoTargetHandler.GotoData gotoData) { - if (element instanceof XmlTagImpl) { - if (SchemaDefinitionsSearch.isTypeElement((XmlTagImpl)element)) { + if (element instanceof XmlTag) { + if (SchemaDefinitionsSearch.isTypeElement((XmlTag)element)) { return new MyRenderer(""); - } else if (SchemaDefinitionsSearch.isElementWithSomeEmbeddedType((XmlTagImpl)element)) { + } else if (SchemaDefinitionsSearch.isElementWithSomeEmbeddedType((XmlTag)element)) { return new MyRenderer("xsd:element: "); } } return null; } - private static class MyRenderer extends PsiElementListCellRenderer { + private static class MyRenderer extends PsiElementListCellRenderer { private final String myPrefix; private MyRenderer(String prefix) { @@ -45,13 +45,13 @@ public class GotoXmlSchemaTypeRendererProvider implements GotoTargetRendererProv } @Override - public String getElementText(XmlTagImpl element) { + public String getElementText(XmlTag element) { final XmlAttribute attr = SchemaDefinitionsSearch.getNameAttr(element); return myPrefix + (attr == null || attr.getValue() == null ? element.getName() : attr.getValue()); } @Override - protected String getContainerText(XmlTagImpl element, String name) { + protected String getContainerText(XmlTag element, String name) { final PsiFile file = element.getContainingFile(); return "(" + file.getName() + ")"; } diff --git a/xml/impl/src/com/intellij/xml/impl/schema/SchemaDefinitionsSearch.java b/xml/impl/src/com/intellij/xml/impl/schema/SchemaDefinitionsSearch.java index 3c60dbd422f7..fcc228e99e1f 100644 --- a/xml/impl/src/com/intellij/xml/impl/schema/SchemaDefinitionsSearch.java +++ b/xml/impl/src/com/intellij/xml/impl/schema/SchemaDefinitionsSearch.java @@ -10,14 +10,12 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; -import com.intellij.psi.impl.source.xml.XmlTagImpl; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.Processor; import com.intellij.util.QueryExecutor; -import java.util.HashSet; import com.intellij.xml.index.SchemaTypeInfo; import com.intellij.xml.index.SchemaTypeInheritanceIndex; import com.intellij.xml.index.XmlNamespaceIndex; @@ -30,8 +28,8 @@ import java.util.function.BiFunction; public class SchemaDefinitionsSearch implements QueryExecutor { @Override public boolean execute(@NotNull final PsiElement queryParameters, @NotNull final Processor consumer) { - if (queryParameters instanceof XmlTagImpl) { - final XmlTagImpl xml = (XmlTagImpl) queryParameters; + if (queryParameters instanceof XmlTag) { + final XmlTag xml = (XmlTag)queryParameters; if (ReadAction.compute(() -> isTypeElement(xml))) { final Collection infos = ReadAction.compute(() -> gatherInheritors(xml)); @@ -70,9 +68,9 @@ public class SchemaDefinitionsSearch implements QueryExecutor gatherInheritors(XmlTagImpl xml) { + private Collection gatherInheritors(XmlTag xml) { XmlAttribute name = getNameAttr(xml); if (name == null || StringUtil.isEmptyOrSpaces(name.getValue())) return null; String localName = name.getValue(); @@ -184,7 +182,7 @@ public class SchemaDefinitionsSearch implements QueryExecutor implements ICompositeElementType, IXmlTagElementType { + + public HtmlStubBasedTagElementType(@NotNull String debugName, + @NotNull Language language) { + super(debugName, language); + } + + @Override + public void serialize(@NotNull XmlTagStubImpl stub, @NotNull StubOutputStream dataStream) throws IOException { + stub.serialize(dataStream); + } + + @NotNull + @Override + public XmlTagStubImpl deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException { + return new XmlTagStubImpl(parentStub, dataStream, this); + } + + @Override + @NotNull + public HtmlStubBasedTagImpl createPsi(@NotNull XmlTagStubImpl stub) { + return new HtmlStubBasedTagImpl(stub, this); + } + + @Override + @NotNull + public HtmlStubBasedTagImpl createPsi(@NotNull ASTNode node) { + return new HtmlStubBasedTagImpl(node); + } + + @NotNull + @Override + public XmlTagStubImpl createStub(@NotNull HtmlStubBasedTagImpl psi, StubElement parentStub) { + return new XmlTagStubImpl(psi, parentStub, this); + } + +} diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/HtmlStubBasedTagImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/HtmlStubBasedTagImpl.java new file mode 100644 index 000000000000..7611c744a4b7 --- /dev/null +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/HtmlStubBasedTagImpl.java @@ -0,0 +1,130 @@ +// 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.psi.impl.source.html; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.html.HtmlTag; +import com.intellij.psi.impl.source.xml.XmlStubBasedTag; +import com.intellij.psi.impl.source.xml.XmlTagDelegate; +import com.intellij.psi.impl.source.xml.stub.XmlTagStubImpl; +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlTag; +import com.intellij.xml.util.XmlUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class HtmlStubBasedTagImpl extends XmlStubBasedTag implements HtmlTag { + public HtmlStubBasedTagImpl(@NotNull XmlTagStubImpl stub, + @NotNull IStubElementType nodeType) { + super(stub, nodeType); + } + + public HtmlStubBasedTagImpl(@NotNull ASTNode node) { + super(node); + } + + @Override + @NotNull + public XmlTag[] findSubTags(@NotNull String name, String namespace) { + final XmlTag[] subTags = getSubTags(); + List result = null; + + for (final XmlTag subTag : subTags) { + if (namespace == null) { + String tagName = subTag.getName(); + tagName = StringUtil.toLowerCase(tagName); + + if (name == null || name.equals(tagName)) { + if (result == null) { + result = new ArrayList<>(3); + } + + result.add(subTag); + } + } + else if (namespace.equals(subTag.getNamespace()) && + (name == null || name.equals(subTag.getLocalName())) + ) { + if (result == null) { + result = new ArrayList<>(3); + } + + result.add(subTag); + } + } + + return result == null ? EMPTY : result.toArray(XmlTag.EMPTY); + } + + @Override + public String getAttributeValue(String qname) { + qname = StringUtil.toLowerCase(qname); + return super.getAttributeValue(qname); + } + + @Override + public String getAttributeValue(String name, String namespace) { + name = StringUtil.toLowerCase(name); + return super.getAttributeValue(name, namespace); + } + + @Override + @NotNull + public String getNamespace() { + final String xmlNamespace = super.getNamespace(); + + if (!getNamespacePrefix().isEmpty()) { + return xmlNamespace; + } + + if (xmlNamespace.isEmpty() || xmlNamespace.equals(XmlUtil.XHTML_URI)) { + return XmlUtil.HTML_URI; + } + + // ex.: mathML and SVG namespaces can be used inside html file + return xmlNamespace; + } + + @Nullable + @Override + public String getRealNs(@Nullable final String value) { + if (XmlUtil.XHTML_URI.equals(value)) return XmlUtil.HTML_URI; + return value; + } + + @Override + public String toString() { + return "HtmlTag:" + getName(); + } + + @Override + public String getPrefixByNamespace(String namespace) { + if (XmlUtil.HTML_URI.equals(namespace)) namespace = XmlUtil.XHTML_URI; + return super.getPrefixByNamespace(namespace); + } + + @Override + public XmlTag getParentTag() { + return PsiTreeUtil.getParentOfType(this, XmlTag.class); + } + + @NotNull + @Override + protected XmlTagDelegate createDelegate() { + return new HtmlTagImplDelegate(); + } + + private class HtmlTagImplDelegate extends XmlStubBasedTagDelegate { + @Override + protected void cacheOneAttributeValue(String name, String value, final Map attributesValueMap) { + name = StringUtil.toLowerCase(name); + super.cacheOneAttributeValue(name, value, attributesValueMap); + } + } + +} diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/parsing/xml/XmlBuilderDriver.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/parsing/xml/XmlBuilderDriver.java index c52bc83f6270..987b4ed30920 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/parsing/xml/XmlBuilderDriver.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/parsing/xml/XmlBuilderDriver.java @@ -28,6 +28,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.TokenType; import com.intellij.psi.tree.IElementType; import com.intellij.psi.xml.IXmlAttributeElementType; +import com.intellij.psi.xml.IXmlTagElementType; import com.intellij.psi.xml.XmlElementType; import com.intellij.psi.xml.XmlTokenType; import com.intellij.util.containers.Stack; @@ -70,7 +71,7 @@ public class XmlBuilderDriver { for (int i = 0; i < count; i++) { LighterASTNode child = children[i]; final IElementType tt = child.getTokenType(); - if (tt == XmlElementType.XML_TAG || tt == XmlElementType.HTML_TAG) { + if (tt instanceof IXmlTagElementType) { processTagNode(b, structure, child, builder); } else if (tt == XmlElementType.XML_PROLOG) { @@ -154,7 +155,7 @@ public class XmlBuilderDriver { LighterASTNode node, XmlBuilder builder) { final IElementType nodeTT = node.getTokenType(); - assert nodeTT == XmlElementType.XML_TAG || nodeTT == XmlElementType.HTML_TAG; + assert nodeTT instanceof IXmlTagElementType; final Ref childrenRef = Ref.create(null); final int count = structure.getChildren(node, childrenRef); @@ -190,7 +191,7 @@ public class XmlBuilderDriver { LighterASTNode child = children[i]; IElementType tt = child.getTokenType(); if (tt == TokenType.ERROR_ELEMENT) processErrorNode(psiBuilder, child, builder); - if (tt == XmlElementType.XML_TAG || tt == XmlElementType.HTML_TAG) processTagNode(psiBuilder, structure, child, builder); + if (tt instanceof IXmlTagElementType) processTagNode(psiBuilder, structure, child, builder); if (processAttrs && tt instanceof IXmlAttributeElementType) processAttributeNode(child, structure, builder); if (processTexts && tt == XmlElementType.XML_TEXT) processTextNode(structure, child, builder); if (tt == XmlElementType.XML_ENTITY_REF) builder.entityRef(getTokenText(child), child.getStartOffset(), child.getEndOffset()); diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlStubBasedElement.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlStubBasedElement.java index dfdbf0223a30..b22e63085a4c 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlStubBasedElement.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlStubBasedElement.java @@ -10,12 +10,16 @@ import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.SearchScope; import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.stubs.StubElement; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.psi.xml.XmlElement; import com.intellij.psi.xml.XmlTag; import com.intellij.xml.util.XmlPsiUtil; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + /** * Simplified stub-based version of {@link XmlElementImpl} * @@ -41,7 +45,7 @@ abstract class XmlStubBasedElement> extends StubBasedPs @Override public PsiElement getContext() { final XmlElement data = getUserData(INCLUDING_ELEMENT); - if(data != null) return data; + if (data != null) return data; return super.getContext(); } @@ -64,9 +68,10 @@ abstract class XmlStubBasedElement> extends StubBasedPs @Override public PsiElement getParent() { final XmlElement data = getUserData(INCLUDING_ELEMENT); - if(data != null) return data; + if (data != null) return data; return super.getParent(); } + @Override @NotNull public Language getLanguage() { @@ -105,6 +110,20 @@ abstract class XmlStubBasedElement> extends StubBasedPs putUserData(DO_NOT_VALIDATE, null); } + @Override + @NotNull + public PsiElement[] getChildren() { + PsiElement psiChild = getFirstChild(); + if (psiChild == null) return PsiElement.EMPTY_ARRAY; + + List result = new ArrayList<>(); + while (psiChild != null) { + result.add(psiChild); + psiChild = psiChild.getNextSibling(); + } + return PsiUtilCore.toPsiElementArray(result); + } + @Override public String toString() { return "PsiElement" + "(" + getElementType() + ")"; diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlStubBasedTagBase.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlStubBasedTagBase.java index 30562040554d..4b8e9d03e0a8 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlStubBasedTagBase.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlStubBasedTagBase.java @@ -65,6 +65,8 @@ public class XmlStubBasedTagBase> public void subtreeChanged() { super.subtreeChanged(); myImpl = null; + myValue = null; + myAttributes = null; } @Override @@ -207,6 +209,7 @@ public class XmlStubBasedTagBase> return getImpl().getAttribute(qname); } + @Override public boolean isCaseSensitive() { return true; } @@ -374,11 +377,6 @@ public class XmlStubBasedTagBase> super(XmlStubBasedTagBase.this); } - @Override - protected boolean isCaseSensitive() { - return XmlStubBasedTagBase.this.isCaseSensitive(); - } - @Override protected void deleteChildInternalSuper(@NotNull ASTNode child) { XmlStubBasedTagBase.super.deleteChildInternal(child); diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagDelegate.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagDelegate.java index d83335c79a16..71274e4875cc 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagDelegate.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagDelegate.java @@ -73,8 +73,6 @@ public abstract class XmlTagDelegate { myTag = tag; } - protected abstract boolean isCaseSensitive(); - protected abstract void deleteChildInternalSuper(@NotNull final ASTNode child); protected abstract TreeElement addInternalSuper(TreeElement first, ASTNode last, @Nullable ASTNode anchor, @Nullable Boolean before); @@ -690,7 +688,7 @@ public abstract class XmlTagDelegate { if (qname == null) return null; final XmlAttribute[] attributes = myTag.getAttributes(); - final boolean caseSensitive = isCaseSensitive(); + final boolean caseSensitive = myTag.isCaseSensitive(); for (final XmlAttribute attribute : attributes) { final ASTNode child = XmlChildRole.ATTRIBUTE_NAME_FINDER.findChild(attribute.getNode()); @@ -1075,8 +1073,8 @@ public abstract class XmlTagDelegate { // insert child just after anchor // insert into the position specified by index if (subTagNum >= 0) { - final ASTNode subTag = (ASTNode)subTags[subTagNum]; - if (subTag.getTreeParent() != myTag) { + final ASTNode subTag = subTags[subTagNum].getNode(); + if (subTag.getTreeParent() != myTag.getNode()) { // in entity final XmlEntityRef entityRef = PsiTreeUtil.getParentOfType(subTags[subTagNum], XmlEntityRef.class); throw new IncorrectOperationException( 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 9065581cc444..2afdba388b6e 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 @@ -224,10 +224,6 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag, HintedReferenc return getImpl().getAttribute(qname); } - public boolean isCaseSensitive() { - return true; - } - @Override @NotNull public String getNamespace() { @@ -390,11 +386,6 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag, HintedReferenc super(XmlTagImpl.this); } - @Override - protected boolean isCaseSensitive() { - return XmlTagImpl.this.isCaseSensitive(); - } - @Override protected void deleteChildInternalSuper(@NotNull ASTNode child) { XmlTagImpl.super.deleteChildInternal(child); diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java index f003b561c501..13626bbc0af3 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java @@ -82,7 +82,7 @@ public class XmlTagValueImpl implements XmlTagValue{ @NotNull public TextRange getTextRange() { if(myElements.length == 0){ - final ASTNode child = XmlChildRole.START_TAG_END_FINDER.findChild( (ASTNode)myTag); + final ASTNode child = XmlChildRole.START_TAG_END_FINDER.findChild(myTag.getNode()); if(child != null) return new TextRange(child.getStartOffset() + 1, child.getStartOffset() + 1); return new TextRange(myTag.getTextRange().getEndOffset(), myTag.getTextRange().getEndOffset()); diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlAttributeStubImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlAttributeStubImpl.java index ea5e9c159ee1..8a87083fbff0 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlAttributeStubImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlAttributeStubImpl.java @@ -16,7 +16,7 @@ public class XmlAttributeStubImpl extends StubBase implem @NotNull private final String name; @Nullable private final String value; - XmlAttributeStubImpl(@Nullable StubElement parent, + public XmlAttributeStubImpl(@Nullable StubElement parent, @NotNull StubInputStream dataStream, @NotNull IStubElementType elementType) throws IOException { @@ -25,7 +25,7 @@ public class XmlAttributeStubImpl extends StubBase implem value = StringRef.toString(dataStream.readName()); } - XmlAttributeStubImpl(@NotNull XmlStubBasedAttribute psi, + public XmlAttributeStubImpl(@NotNull XmlStubBasedAttribute psi, @Nullable StubElement parent, @NotNull IStubElementType elementType) { super(parent, elementType); diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedAttributeElementType.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedAttributeElementType.java index 135ee3bc3aed..677aecc7501b 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedAttributeElementType.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedAttributeElementType.java @@ -3,24 +3,23 @@ package com.intellij.psi.impl.source.xml.stub; import com.intellij.lang.ASTNode; import com.intellij.lang.Language; -import com.intellij.psi.impl.source.tree.CompositeElement; import com.intellij.psi.impl.source.xml.XmlStubBasedAttribute; -import com.intellij.psi.stubs.*; +import com.intellij.psi.stubs.StubElement; +import com.intellij.psi.stubs.StubInputStream; +import com.intellij.psi.stubs.StubOutputStream; import com.intellij.psi.tree.ICompositeElementType; +import com.intellij.psi.xml.IXmlAttributeElementType; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.util.Locale; public class XmlStubBasedAttributeElementType - extends IStubElementType implements ICompositeElementType { + extends XmlStubBasedElementType implements ICompositeElementType, IXmlAttributeElementType { - private final @NotNull String externalId; public XmlStubBasedAttributeElementType(@NotNull String debugName, @NotNull Language language) { - super(language.getID().toUpperCase(Locale.ENGLISH) + ":" + debugName, language); - externalId = language.getID().toUpperCase(Locale.ENGLISH) + ":" + debugName; + super(debugName, language); } @Override @@ -34,36 +33,22 @@ public class XmlStubBasedAttributeElementType return new XmlAttributeStubImpl(parentStub, dataStream, this); } - @Override - public void indexStub(@NotNull XmlAttributeStubImpl stub, @NotNull IndexSink sink) { - } - @Override @NotNull public XmlStubBasedAttribute createPsi(@NotNull XmlAttributeStubImpl stub) { return new XmlStubBasedAttribute(stub, this); } + @Override @NotNull public XmlStubBasedAttribute createPsi(@NotNull ASTNode node) { return new XmlStubBasedAttribute(node); } - @NotNull - @Override - public String getExternalId() { - return externalId; - } - @NotNull @Override public XmlAttributeStubImpl createStub(@NotNull XmlStubBasedAttribute psi, StubElement parentStub) { return new XmlAttributeStubImpl(psi, parentStub, this); } - @NotNull - @Override - public ASTNode createCompositeNode() { - return new CompositeElement(this); - } } diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedElementType.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedElementType.java new file mode 100644 index 000000000000..01704a801fbb --- /dev/null +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedElementType.java @@ -0,0 +1,46 @@ +// 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.psi.impl.source.xml.stub; + +import com.intellij.lang.ASTNode; +import com.intellij.lang.Language; +import com.intellij.lang.xml.XMLLanguage; +import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.source.tree.CompositeElement; +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.stubs.IndexSink; +import com.intellij.psi.stubs.StubElement; +import com.intellij.psi.tree.ICompositeElementType; +import org.jetbrains.annotations.NotNull; + +import java.util.Locale; + +public abstract class XmlStubBasedElementType, PsiT extends PsiElement> + extends IStubElementType implements ICompositeElementType { + + private final @NotNull String externalId; + + public XmlStubBasedElementType(@NotNull String debugName, + @NotNull Language language) { + super((language == XMLLanguage.INSTANCE ? "" : language.getID().toUpperCase(Locale.ENGLISH) + ":") + debugName, language); + externalId = (language == XMLLanguage.INSTANCE ? "" : language.getID().toUpperCase(Locale.ENGLISH) + ":") + debugName; + } + + @Override + public void indexStub(@NotNull StubT stub, @NotNull IndexSink sink) { + } + + @NotNull + public abstract PsiT createPsi(@NotNull ASTNode node); + + @NotNull + @Override + public String getExternalId() { + return externalId; + } + + @NotNull + @Override + public ASTNode createCompositeNode() { + return new CompositeElement(this); + } +} diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedTagElementType.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedTagElementType.java index 16287ae760e4..eb44fad286e2 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedTagElementType.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlStubBasedTagElementType.java @@ -3,24 +3,22 @@ package com.intellij.psi.impl.source.xml.stub; import com.intellij.lang.ASTNode; import com.intellij.lang.Language; -import com.intellij.psi.impl.source.tree.CompositeElement; import com.intellij.psi.impl.source.xml.XmlStubBasedTag; -import com.intellij.psi.stubs.*; +import com.intellij.psi.stubs.StubElement; +import com.intellij.psi.stubs.StubInputStream; +import com.intellij.psi.stubs.StubOutputStream; import com.intellij.psi.tree.ICompositeElementType; +import com.intellij.psi.xml.IXmlTagElementType; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.util.Locale; public class XmlStubBasedTagElementType - extends IStubElementType implements ICompositeElementType { - - private final @NotNull String externalId; + extends XmlStubBasedElementType implements ICompositeElementType, IXmlTagElementType { public XmlStubBasedTagElementType(@NotNull String debugName, @NotNull Language language) { - super(language.getID().toUpperCase(Locale.ENGLISH) + ":" + debugName, language); - externalId = language.getID().toUpperCase(Locale.ENGLISH) + ":" + debugName; + super(debugName, language); } @Override @@ -34,36 +32,22 @@ public class XmlStubBasedTagElementType return new XmlTagStubImpl(parentStub, dataStream, this); } - @Override - public void indexStub(@NotNull XmlTagStubImpl stub, @NotNull IndexSink sink) { - } - @Override @NotNull public XmlStubBasedTag createPsi(@NotNull XmlTagStubImpl stub) { return new XmlStubBasedTag(stub, this); } + @Override @NotNull public XmlStubBasedTag createPsi(@NotNull ASTNode node) { return new XmlStubBasedTag(node); } - @NotNull - @Override - public String getExternalId() { - return externalId; - } - @NotNull @Override public XmlTagStubImpl createStub(@NotNull XmlStubBasedTag psi, StubElement parentStub) { return new XmlTagStubImpl(psi, parentStub, this); } - @NotNull - @Override - public ASTNode createCompositeNode() { - return new CompositeElement(this); - } } diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlTagStubImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlTagStubImpl.java index b3daff4725bf..9a7384ad4509 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlTagStubImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/stub/XmlTagStubImpl.java @@ -15,7 +15,7 @@ public class XmlTagStubImpl extends StubBase implements XmlTagS @NotNull private final String name; - XmlTagStubImpl(@Nullable StubElement parent, + public XmlTagStubImpl(@Nullable StubElement parent, @NotNull StubInputStream dataStream, @NotNull IStubElementType elementType) throws IOException { @@ -23,14 +23,14 @@ public class XmlTagStubImpl extends StubBase implements XmlTagS name = notNull(StringRef.toString(dataStream.readName()), ""); } - XmlTagStubImpl(@NotNull XmlStubBasedTag psi, + public XmlTagStubImpl(@NotNull XmlStubBasedTag psi, @Nullable StubElement parent, @NotNull IStubElementType elementType) { super(parent, elementType); name = psi.getName(); } - void serialize(StubOutputStream stream) throws IOException { + public void serialize(StubOutputStream stream) throws IOException { stream.writeName(name); } diff --git a/xml/xml-psi-impl/src/com/intellij/psi/xml/IXmlTagElementType.java b/xml/xml-psi-impl/src/com/intellij/psi/xml/IXmlTagElementType.java new file mode 100644 index 000000000000..8eb461cf67a7 --- /dev/null +++ b/xml/xml-psi-impl/src/com/intellij/psi/xml/IXmlTagElementType.java @@ -0,0 +1,5 @@ +// 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.psi.xml; + +public interface IXmlTagElementType { +} diff --git a/xml/xml-psi-impl/src/com/intellij/psi/xml/XmlElementType.java b/xml/xml-psi-impl/src/com/intellij/psi/xml/XmlElementType.java index a73958308351..fb04b7a417f8 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/xml/XmlElementType.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/xml/XmlElementType.java @@ -23,6 +23,7 @@ import com.intellij.lang.xhtml.XHTMLLanguage; import com.intellij.lang.xml.XMLLanguage; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.source.parsing.xml.DtdParsing; +import com.intellij.psi.stubs.PsiFileStub; import com.intellij.psi.tree.*; import com.intellij.psi.tree.xml.IXmlElementType; import com.intellij.util.CharTable; @@ -37,7 +38,7 @@ public interface XmlElementType extends XmlTokenType { IElementType XML_DOCTYPE = new IXmlElementType("XML_DOCTYPE"); IElementType XML_ATTRIBUTE = new XmlAttributeElementType(); IElementType XML_COMMENT = new IXmlElementType("XML_COMMENT"); - IElementType XML_TAG = new IXmlElementType("XML_TAG"); + IElementType XML_TAG = new XmlTagElementType("XML_TAG"); IElementType XML_ELEMENT_DECL = new IXmlElementType("XML_ELEMENT_DECL"); IElementType XML_CONDITIONAL_SECTION = new IXmlElementType("XML_CONDITIONAL_SECTION"); @@ -55,11 +56,11 @@ public interface XmlElementType extends XmlTokenType { //todo: move to html IElementType HTML_DOCUMENT = new IXmlElementType("HTML_DOCUMENT"); - IElementType HTML_TAG = new IXmlElementType("HTML_TAG"); - IFileElementType HTML_FILE = new IStubFileElementType(HTMLLanguage.INSTANCE) { + IElementType HTML_TAG = new XmlTagElementType("HTML_TAG"); + IFileElementType HTML_FILE = new IStubFileElementType>(HTMLLanguage.INSTANCE) { @Override public int getStubVersion() { - return super.getStubVersion() + 1; + return super.getStubVersion() + 2; } }; IElementType HTML_EMBEDDED_CONTENT = new EmbeddedHtmlContentElementType(); @@ -72,7 +73,7 @@ public interface XmlElementType extends XmlTokenType { IFileElementType DTD_FILE = new IFileElementType("DTD_FILE", DTDLanguage.INSTANCE); - IElementType XML_MARKUP_DECL = new CustomParsingType("XML_MARKUP_DECL", XMLLanguage.INSTANCE){ + IElementType XML_MARKUP_DECL = new CustomParsingType("XML_MARKUP_DECL", XMLLanguage.INSTANCE) { @NotNull @Override public ASTNode parse(@NotNull CharSequence text, @NotNull CharTable table) { @@ -96,6 +97,10 @@ public interface XmlElementType extends XmlTokenType { } } + final class XmlTagElementType extends IXmlElementType implements IXmlTagElementType { + public XmlTagElementType(String debugName) {super(debugName);} + } + final class XmlAttributeElementType extends IXmlElementType implements IXmlAttributeElementType { public XmlAttributeElementType() {super("XML_ATTRIBUTE");} } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java index b76ee6dbd4d4..3e8392219b97 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java @@ -31,7 +31,6 @@ import com.intellij.psi.impl.source.html.HtmlDocumentImpl; import com.intellij.psi.impl.source.parsing.xml.HtmlBuilderDriver; import com.intellij.psi.impl.source.parsing.xml.XmlBuilder; import com.intellij.psi.impl.source.tree.CompositeElement; -import com.intellij.psi.impl.source.xml.XmlTagImpl; import com.intellij.psi.templateLanguages.OuterLanguageElement; import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider; import com.intellij.psi.util.PsiTreeUtil; @@ -136,7 +135,7 @@ public class HtmlUtil { public static boolean isSingleHtmlTag(@NotNull XmlTag tag, boolean lowerCase) { final XmlExtension extension = XmlExtension.getExtensionByElement(tag); final String name = tag.getName(); - boolean result = EMPTY_TAGS_MAP.contains(!lowerCase || tag instanceof XmlTagImpl && ((XmlTagImpl)tag).isCaseSensitive() + boolean result = EMPTY_TAGS_MAP.contains(!lowerCase || tag.isCaseSensitive() ? name : StringUtil.toLowerCase(name)); return result && (extension == null || !extension.isSingleTagException(tag)); } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/util/documentation/HtmlCompatibilityData.java b/xml/xml-psi-impl/src/com/intellij/xml/util/documentation/HtmlCompatibilityData.java index f5dcac7c6d38..3fd68cb4fd87 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/util/documentation/HtmlCompatibilityData.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/util/documentation/HtmlCompatibilityData.java @@ -6,7 +6,6 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.impl.source.xml.XmlTagImpl; import com.intellij.psi.xml.XmlTag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -67,7 +66,7 @@ public class HtmlCompatibilityData { @Nullable public static Map getTagData(@Nullable XmlTag tag) { if (tag == null) return null; - String key = tag instanceof XmlTagImpl && ((XmlTagImpl)tag).isCaseSensitive() ? + String key = tag.isCaseSensitive() ? tag.getName() : StringUtil.toLowerCase(tag.getName()); if ("input".equals(key)) { @@ -83,8 +82,8 @@ public class HtmlCompatibilityData { PsiElement element = tag; while (element != null && !(element instanceof PsiFile)) { if (element instanceof XmlTag) { - String name = element instanceof XmlTagImpl && ((XmlTagImpl)tag).isCaseSensitive() ? - ((XmlTagImpl)element).getName() : + String name = tag.isCaseSensitive() ? + ((XmlTag)element).getName() : StringUtil.toLowerCase(((XmlTag)element).getName()); if (MATH.equals(name)) {