mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
xinclude support for stubbed dom
This commit is contained in:
@@ -28,6 +28,7 @@ import com.intellij.psi.SmartPointerManager;
|
||||
import com.intellij.psi.SmartPsiElementPointer;
|
||||
import com.intellij.psi.XmlElementFactory;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubs.Stub;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.psi.xml.XmlAttribute;
|
||||
import com.intellij.psi.xml.XmlElement;
|
||||
@@ -40,10 +41,7 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.xml.*;
|
||||
import com.intellij.util.xml.events.DomEvent;
|
||||
import com.intellij.util.xml.reflect.*;
|
||||
import com.intellij.util.xml.stubs.AttributeStub;
|
||||
import com.intellij.util.xml.stubs.DomStub;
|
||||
import com.intellij.util.xml.stubs.ElementStub;
|
||||
import com.intellij.util.xml.stubs.StubParentStrategy;
|
||||
import com.intellij.util.xml.stubs.*;
|
||||
import net.sf.cglib.proxy.AdvancedProxy;
|
||||
import net.sf.cglib.proxy.InvocationHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -62,8 +60,8 @@ import java.util.List;
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public abstract class DomInvocationHandler<T extends AbstractDomChildDescriptionImpl, Stub extends DomStub> extends UserDataHolderBase implements InvocationHandler, DomElement,
|
||||
SemElement {
|
||||
public abstract class DomInvocationHandler<T extends AbstractDomChildDescriptionImpl, S extends DomStub> extends UserDataHolderBase implements InvocationHandler, DomElement,
|
||||
SemElement {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.util.xml.impl.DomInvocationHandler");
|
||||
public static final Method ACCEPT_METHOD = ReflectionUtil.getMethod(DomElement.class, "accept", DomElementVisitor.class);
|
||||
public static final Method ACCEPT_CHILDREN_METHOD = ReflectionUtil.getMethod(DomElement.class, "acceptChildren", DomElementVisitor.class);
|
||||
@@ -81,14 +79,14 @@ public abstract class DomInvocationHandler<T extends AbstractDomChildDescription
|
||||
private final InvocationCache myInvocationCache;
|
||||
private volatile Converter myScalarConverter = null;
|
||||
private volatile SmartFMap<Method, Invocation> myAccessorInvocations = SmartFMap.emptyMap();
|
||||
@Nullable protected Stub myStub;
|
||||
@Nullable protected S myStub;
|
||||
|
||||
protected DomInvocationHandler(Type type, DomParentStrategy parentStrategy,
|
||||
@NotNull final EvaluatedXmlName tagName,
|
||||
final T childDescription,
|
||||
final DomManagerImpl manager,
|
||||
boolean dynamic,
|
||||
@Nullable Stub stub) {
|
||||
@Nullable S stub) {
|
||||
myManager = manager;
|
||||
myParentStrategy = parentStrategy;
|
||||
myTagName = tagName;
|
||||
@@ -129,7 +127,7 @@ public abstract class DomInvocationHandler<T extends AbstractDomChildDescription
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Stub getStub() {
|
||||
public S getStub() {
|
||||
return myStub;
|
||||
}
|
||||
|
||||
@@ -839,13 +837,15 @@ public abstract class DomInvocationHandler<T extends AbstractDomChildDescription
|
||||
if (description instanceof DomChildDescriptionImpl) {
|
||||
XmlName xmlName = ((DomChildDescriptionImpl)description).getXmlName();
|
||||
List<DomStub> stubs = myStub.getChildrenByName(xmlName.getLocalName(), xmlName.getNamespaceKey());
|
||||
return ContainerUtil.map(stubs, stub -> stub.getOrCreateHandler((DomChildDescriptionImpl)description, myManager).getProxy());
|
||||
List<DomElement> elements =
|
||||
ContainerUtil.map(stubs, stub -> stub.getOrCreateHandler((DomChildDescriptionImpl)description, myManager).getProxy());
|
||||
return addIncludedElements(elements, xmlName);
|
||||
}
|
||||
else if (description instanceof CustomDomChildrenDescriptionImpl) {
|
||||
List<DomStub> stubs = myStub.getChildrenStubs();
|
||||
return ContainerUtil.mapNotNull(stubs, (NullableFunction<DomStub, DomElement>)stub -> {
|
||||
if (stub instanceof ElementStub && stub.isCustom()) {
|
||||
EvaluatedXmlName name = new DummyEvaluatedXmlName(stub.getName(), "");
|
||||
List<? extends Stub> stubs = myStub.getChildrenStubs();
|
||||
return ContainerUtil.mapNotNull(stubs, (NullableFunction<Stub, DomElement>)stub -> {
|
||||
if (stub instanceof ElementStub && ((ElementStub)stub).isCustom()) {
|
||||
EvaluatedXmlName name = new DummyEvaluatedXmlName(((ElementStub)stub).getName(), "");
|
||||
return new CollectionElementInvocationHandler(name, (CustomDomChildrenDescriptionImpl)description, myManager, (ElementStub)stub).getProxy();
|
||||
}
|
||||
return null;
|
||||
@@ -877,6 +877,17 @@ public abstract class DomInvocationHandler<T extends AbstractDomChildDescription
|
||||
return Collections.unmodifiableList(elements);
|
||||
}
|
||||
|
||||
private List<? extends DomElement> addIncludedElements(List<? extends DomElement> elements, XmlName xmlName) {
|
||||
assert myStub != null;
|
||||
List<DomElement> result = new SmartList<>(elements);
|
||||
for (Stub stub : myStub.getChildrenStubs()) {
|
||||
if (stub instanceof XIncludeStub) {
|
||||
((XIncludeStub)stub).resolve(this, result, xmlName);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<XmlTag> getCollectionSubTags(@NotNull AbstractCollectionChildDescription description, @NotNull XmlTag tag) {
|
||||
if (description instanceof CollectionChildDescriptionImpl) {
|
||||
return ((CollectionChildDescriptionImpl)description).getCollectionSubTags(this, tag);
|
||||
|
||||
@@ -26,5 +26,6 @@ public class DomElementTypeHolder {
|
||||
SerializationManager.getInstance().registerSerializer(ElementStubSerializer.INSTANCE);
|
||||
SerializationManager.getInstance().registerSerializer(AttributeStubSerializer.INSTANCE);
|
||||
SerializationManager.getInstance().registerSerializer(FileStubSerializer.INSTANCE);
|
||||
SerializationManager.getInstance().registerSerializer(XIncludeStub.ourSerializer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.util.xml.stubs;
|
||||
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.stubs.ObjectStubBase;
|
||||
import com.intellij.psi.stubs.Stub;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.io.StringRef;
|
||||
import com.intellij.util.xml.EvaluatedXmlNameImpl;
|
||||
@@ -50,10 +51,6 @@ public abstract class DomStub extends ObjectStubBase<DomStub> {
|
||||
myLocalName = localName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public abstract List<DomStub> getChildrenStubs();
|
||||
|
||||
public String getName() {
|
||||
return myLocalName.getString();
|
||||
}
|
||||
@@ -64,7 +61,7 @@ public abstract class DomStub extends ObjectStubBase<DomStub> {
|
||||
}
|
||||
|
||||
public List<DomStub> getChildrenByName(final CharSequence name, @Nullable final String nsKey) {
|
||||
final List<DomStub> stubs = getChildrenStubs();
|
||||
final List<? extends Stub> stubs = getChildrenStubs();
|
||||
if (stubs.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -73,10 +70,10 @@ public abstract class DomStub extends ObjectStubBase<DomStub> {
|
||||
final List<DomStub> result = new SmartList<>();
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0, size = stubs.size(); i < size; i++) {
|
||||
final DomStub stub = stubs.get(i);
|
||||
if (XmlUtil.getLocalName(stub.getName()).equals(name) &&
|
||||
Comparing.equal(s, stub.getNamespaceKey())) {
|
||||
result.add(stub);
|
||||
final Stub stub = stubs.get(i);
|
||||
if (stub instanceof DomStub && XmlUtil.getLocalName(((DomStub)stub).getName()).equals(name) &&
|
||||
Comparing.equal(s, ((DomStub)stub).getNamespaceKey())) {
|
||||
result.add((DomStub)stub);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -84,16 +81,16 @@ public abstract class DomStub extends ObjectStubBase<DomStub> {
|
||||
|
||||
@Nullable
|
||||
public AttributeStub getAttributeStub(final XmlName name) {
|
||||
final List<DomStub> stubs = getChildrenStubs();
|
||||
final List<? extends Stub> stubs = getChildrenStubs();
|
||||
if (stubs.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0, size = stubs.size(); i < size; i++) {
|
||||
final DomStub stub = stubs.get(i);
|
||||
final Stub stub = stubs.get(i);
|
||||
if (stub instanceof AttributeStub &&
|
||||
stub.getName().equals(name.getLocalName())) {
|
||||
((AttributeStub)stub).getName().equals(name.getLocalName())) {
|
||||
return (AttributeStub)stub;
|
||||
}
|
||||
}
|
||||
@@ -102,10 +99,10 @@ public abstract class DomStub extends ObjectStubBase<DomStub> {
|
||||
|
||||
@Nullable
|
||||
public ElementStub getElementStub(String name, int index) {
|
||||
List<DomStub> stubs = getChildrenStubs();
|
||||
List<? extends Stub> stubs = getChildrenStubs();
|
||||
int i = 0;
|
||||
for (DomStub stub : stubs) {
|
||||
if (stub instanceof ElementStub && name.equals(stub.getName()) && i++ == index) {
|
||||
for (Stub stub : stubs) {
|
||||
if (stub instanceof ElementStub && name.equals(((ElementStub)stub).getName()) && i++ == index) {
|
||||
return (ElementStub)stub;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.util.xml.stubs;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.stubs.ObjectStubSerializer;
|
||||
import com.intellij.psi.stubs.Stub;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.io.StringRef;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -29,7 +30,7 @@ import java.util.List;
|
||||
*/
|
||||
public class ElementStub extends DomStub {
|
||||
|
||||
private final List<DomStub> myChildren = new SmartList<>();
|
||||
private final List<Stub> myChildren = new SmartList<>();
|
||||
private final int myIndex;
|
||||
private final boolean myCustom;
|
||||
|
||||
@@ -51,13 +52,13 @@ public class ElementStub extends DomStub {
|
||||
myValue = value;
|
||||
}
|
||||
|
||||
void addChild(DomStub child) {
|
||||
void addChild(Stub child) {
|
||||
myChildren.add(child);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<DomStub> getChildrenStubs() {
|
||||
public List<? extends Stub> getChildrenStubs() {
|
||||
return myChildren;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.util.xml.stubs;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.stubs.Stub;
|
||||
import com.intellij.psi.xml.XmlElement;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
@@ -76,7 +77,7 @@ public class StubParentStrategy implements DomParentStrategy {
|
||||
public XmlElement getXmlElement() {
|
||||
DomStub parentStub = myStub.getParentStub();
|
||||
if (parentStub == null) return null;
|
||||
List<DomStub> children = parentStub.getChildrenStubs();
|
||||
List<? extends Stub> children = parentStub.getChildrenStubs();
|
||||
if (children.isEmpty()) return null;
|
||||
XmlTag parentTag = parentStub.getHandler().getXmlTag();
|
||||
if (parentTag == null) return null;
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
// 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.stubs;
|
||||
|
||||
import com.intellij.openapi.fileTypes.PlainTextLanguage;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.PsiFileSystemItem;
|
||||
import com.intellij.psi.impl.source.PsiFileImpl;
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet;
|
||||
import com.intellij.psi.stubs.*;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomElementVisitor;
|
||||
import com.intellij.util.xml.XmlName;
|
||||
import com.intellij.util.xml.impl.DomFileElementImpl;
|
||||
import com.intellij.util.xml.impl.DomInvocationHandler;
|
||||
import com.intellij.util.xmlb.JDOMXIncluder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class XIncludeStub extends ObjectStubBase<ElementStub> {
|
||||
|
||||
private final String myHref;
|
||||
private final String myXpointer;
|
||||
|
||||
public XIncludeStub(ElementStub parent, String href, String xpointer) {
|
||||
super(parent);
|
||||
myHref = href;
|
||||
myXpointer = xpointer;
|
||||
parent.addChild(this);
|
||||
}
|
||||
|
||||
public String getHref() {
|
||||
return myHref;
|
||||
}
|
||||
|
||||
public String getXpointer() {
|
||||
return myXpointer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends Stub> getChildrenStubs() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectStubSerializer getStubType() {
|
||||
return ourSerializer;
|
||||
}
|
||||
|
||||
public void resolve(DomInvocationHandler parent, List<DomElement> included, XmlName xmlName) {
|
||||
if (StringUtil.isEmpty(myHref) || StringUtil.isEmpty(myXpointer)) {
|
||||
return;
|
||||
}
|
||||
Matcher matcher = JDOMXIncluder.XPOINTER_PATTERN.matcher(myXpointer);
|
||||
if (!matcher.matches()) {
|
||||
return;
|
||||
}
|
||||
String group = matcher.group(1);
|
||||
matcher = JDOMXIncluder.CHILDREN_PATTERN.matcher(group);
|
||||
if (!matcher.matches()) {
|
||||
return;
|
||||
}
|
||||
String tagName = matcher.group(1);
|
||||
|
||||
XmlFile file = parent.getFile();
|
||||
PsiFileImpl dummy = (PsiFileImpl)PsiFileFactory.getInstance(file.getProject()).createFileFromText(PlainTextLanguage.INSTANCE, myHref);
|
||||
dummy.setOriginalFile(file);
|
||||
PsiFileSystemItem resolve = new FileReferenceSet(dummy).resolve();
|
||||
if (!(resolve instanceof XmlFile)) {
|
||||
return;
|
||||
}
|
||||
DomFileElementImpl<DomElement> element = parent.getManager().getFileElement((XmlFile)resolve);
|
||||
if (element == null) {
|
||||
return;
|
||||
}
|
||||
DomElement rootElement = element.getRootElement();
|
||||
if (!tagName.equals(rootElement.getXmlElementName())) {
|
||||
return;
|
||||
}
|
||||
rootElement.acceptChildren(new DomElementVisitor() {
|
||||
@Override
|
||||
public void visitDomElement(DomElement element) {
|
||||
if (element.getXmlElementName().equals(xmlName.getLocalName())) {
|
||||
included.add(element);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "href=" + getHref() + " xpointer=" + getXpointer();
|
||||
}
|
||||
|
||||
public final static ObjectStubSerializer ourSerializer = new ObjectStubSerializer<XIncludeStub, ElementStub>() {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getExternalId() {
|
||||
return "XIncludeStub";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(@NotNull XIncludeStub stub, @NotNull StubOutputStream dataStream) throws IOException {
|
||||
dataStream.writeUTFFast(StringUtil.notNullize(stub.getHref()));
|
||||
dataStream.writeUTFFast(StringUtil.notNullize(stub.getXpointer()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public XIncludeStub deserialize(@NotNull StubInputStream dataStream, ElementStub parentStub) throws IOException {
|
||||
return new XIncludeStub(parentStub, dataStream.readUTFFast(), dataStream.readUTFFast());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void indexStub(@NotNull XIncludeStub stub, @NotNull IndexSink sink) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "XInclide";
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -28,6 +28,8 @@ import com.intellij.util.xml.reflect.CustomDomChildrenDescription;
|
||||
import com.intellij.util.xml.reflect.DomChildrenDescription;
|
||||
import com.intellij.util.xml.stubs.AttributeStub;
|
||||
import com.intellij.util.xml.stubs.ElementStub;
|
||||
import com.intellij.util.xml.stubs.XIncludeStub;
|
||||
import com.intellij.xml.util.XmlIncludeHandler;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
@@ -44,6 +46,13 @@ class DomStubBuilderVisitor {
|
||||
}
|
||||
|
||||
void visitXmlElement(XmlElement element, ElementStub parent, int index) {
|
||||
|
||||
if (XmlIncludeHandler.isXInclude(element)) {
|
||||
XmlTag tag = (XmlTag)element;
|
||||
new XIncludeStub(parent, tag.getAttributeValue("href"), tag.getAttributeValue("xpointer"));
|
||||
return;
|
||||
}
|
||||
|
||||
DomInvocationHandler handler = myManager.getDomHandler(element);
|
||||
if (handler == null || handler.getAnnotation(Stubbed.class) == null && !handler.getChildDescription().isStubbed()) return;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.PsiManagerEx;
|
||||
import com.intellij.psi.impl.source.PsiFileImpl;
|
||||
import com.intellij.psi.stubs.ObjectStubTree;
|
||||
import com.intellij.psi.stubs.Stub;
|
||||
import com.intellij.psi.stubs.StubTreeLoader;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
@@ -62,11 +63,11 @@ public class DomStubBuilderTest extends DomStubTest {
|
||||
final ElementStub rootStub = getRootStub("foo.xml");
|
||||
assertEquals("", rootStub.getValue());
|
||||
|
||||
final DomStub fooStub = assertOneElement(rootStub.getChildrenStubs());
|
||||
final Stub fooStub = assertOneElement(rootStub.getChildrenStubs());
|
||||
final ElementStub fooElementStub = assertInstanceOf(fooStub, ElementStub.class);
|
||||
assertEquals("", fooElementStub.getValue());
|
||||
|
||||
final DomStub idStub = ContainerUtil.getFirstItem(fooStub.getChildrenStubs());
|
||||
final Stub idStub = ContainerUtil.getFirstItem(fooStub.getChildrenStubs());
|
||||
final ElementStub idElementStub = assertInstanceOf(idStub, ElementStub.class);
|
||||
assertEquals("foo", idElementStub.getValue());
|
||||
}
|
||||
@@ -107,6 +108,7 @@ public class DomStubBuilderTest extends DomStubTest {
|
||||
myFixture.copyFileToProject("include.xml");
|
||||
doBuilderTest("inclusion.xml", "File:foo\n" +
|
||||
" Element:foo\n" +
|
||||
" XInclide:href=include.xml xpointer=xpointer(/foo/*)\n" +
|
||||
" Element:bar\n" +
|
||||
" Attribute:string:xxx\n" +
|
||||
" Attribute:int:666\n" +
|
||||
@@ -118,7 +120,7 @@ public class DomStubBuilderTest extends DomStubTest {
|
||||
|
||||
DomFileElement<Foo> element = DomManager.getDomManager(getProject()).getFileElement((XmlFile)file, Foo.class);
|
||||
assert element != null;
|
||||
assertEquals(2, element.getRootElement().getBars().size());
|
||||
assertEquals(3, element.getRootElement().getBars().size());
|
||||
}
|
||||
|
||||
public static class TestExtender extends DomExtender<Bar> {
|
||||
|
||||
Reference in New Issue
Block a user