From db22b1730b3e89c7a26d8479a837877274e13ff3 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 9 Aug 2012 20:10:49 +0400 Subject: [PATCH] DOM stubs: accessing attribute values --- .../impl/AttributeChildInvocationHandler.java | 3 + .../util/xml/impl/DomInvocationHandler.java | 24 ++++++- .../xml/impl/DomRootInvocationHandler.java | 3 + .../util/xml/stubs/AttributeStub.java | 3 +- .../com/intellij/util/xml/stubs/DomStub.java | 59 ++++++++++++++++ .../intellij/util/xml/stubs/ElementStub.java | 3 +- .../util/xml/stubs/StubParentStrategy.java | 69 +++++++++++++++++++ .../util/xml/EvaluatedXmlNameImpl.java | 4 +- xml/dom-tests/testData/stubs/foo.xml | 2 +- .../com/intellij/util/xml/stubs/Bar.java | 5 +- .../util/xml/stubs/DomStubBuilderTest.java | 3 +- .../util/xml/stubs/DomStubUsingTest.java | 45 +++++++++++- 12 files changed, 210 insertions(+), 13 deletions(-) create mode 100644 xml/dom-impl/src/com/intellij/util/xml/stubs/StubParentStrategy.java diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/AttributeChildInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/AttributeChildInvocationHandler.java index 502a2c0a64f2..e25a79707533 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/AttributeChildInvocationHandler.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/AttributeChildInvocationHandler.java @@ -129,6 +129,9 @@ public class AttributeChildInvocationHandler extends DomInvocationHandler myAccessorInvocations = SmartFMap.emptyMap(); - @Nullable private final Stub myStub; + @Nullable protected final Stub myStub; protected DomInvocationHandler(Type type, DomParentStrategy parentStrategy, - final EvaluatedXmlName tagName, + @NotNull final EvaluatedXmlName tagName, final T childDescription, final DomManagerImpl manager, boolean dynamic, @@ -576,6 +580,12 @@ public abstract class DomInvocationHandler getCollectionChildren(final AbstractCollectionChildDescription description, final NotNullFunction> tagsGetter) { + if (myStub != null && description.getAnnotation(Stubbed.class) != null) { + XmlName xmlName = ((DomChildDescriptionImpl)description).getXmlName(); + List stubs = myStub.getChildrenByName(xmlName); + return ContainerUtil.map(stubs, new Function() { + @Override + public DomElement fun(DomStub stub) { + return stub.getOrCreateHandler((DomChildDescriptionImpl)description, myManager).getProxy(); + } + }); + } XmlTag tag = getXmlTag(); if (tag == null) return Collections.emptyList(); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java index 39740114bbac..5083161ab1e8 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java @@ -43,6 +43,9 @@ public class DomRootInvocationHandler extends DomInvocationHandler getChildrenStubs() { + public List getChildrenStubs() { return Collections.emptyList(); } diff --git a/xml/dom-impl/src/com/intellij/util/xml/stubs/DomStub.java b/xml/dom-impl/src/com/intellij/util/xml/stubs/DomStub.java index dceaa9500a2a..3d432aa9effa 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/stubs/DomStub.java +++ b/xml/dom-impl/src/com/intellij/util/xml/stubs/DomStub.java @@ -15,8 +15,19 @@ */ package com.intellij.util.xml.stubs; +import com.intellij.openapi.util.Condition; import com.intellij.psi.stubs.ObjectStubBase; +import com.intellij.psi.xml.XmlTag; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.StringRef; +import com.intellij.util.xml.EvaluatedXmlNameImpl; +import com.intellij.util.xml.XmlName; +import com.intellij.util.xml.impl.DomChildDescriptionImpl; +import com.intellij.util.xml.impl.DomInvocationHandler; +import com.intellij.util.xml.impl.DomManagerImpl; +import org.jetbrains.annotations.Nullable; + +import java.util.List; /** * @author Dmitry Avdeev @@ -25,6 +36,7 @@ import com.intellij.util.io.StringRef; public abstract class DomStub extends ObjectStubBase { protected final StringRef myName; + private DomInvocationHandler myHandler; public DomStub(DomStub parent, StringRef name) { super(parent); @@ -34,7 +46,54 @@ public abstract class DomStub extends ObjectStubBase { myName = name; } + public abstract List getChildrenStubs(); + public String getName() { return myName.getString(); } + + public List getChildrenByName(final XmlName name) { + return ContainerUtil.filter(getChildrenStubs(), new Condition() { + @Override + public boolean value(DomStub stub) { + return stub.getName().equals(name.getLocalName()); + } + }); + } + + @Nullable + public AttributeStub getAttributeStub(final XmlName name) { + return (AttributeStub)ContainerUtil.find(getChildrenStubs(), new Condition() { + @Override + public boolean value(DomStub o) { + return o instanceof AttributeStub && o.getName().equals(name.getLocalName()); + } + }); + } + + public synchronized DomInvocationHandler getOrCreateHandler(DomChildDescriptionImpl description, DomManagerImpl manager) { + if (myHandler == null) { + XmlName name = description.getXmlName(); + EvaluatedXmlNameImpl evaluatedXmlName = EvaluatedXmlNameImpl.createEvaluatedXmlName(name, name.getNamespaceKey(), true); + myHandler = new DomInvocationHandler(description.getType(), new StubParentStrategy(this), evaluatedXmlName, description, manager, false, this) { + @Override + protected void undefineInternal() { + } + + @Override + protected XmlTag setEmptyXmlTag() { + return null; + } + }; + } + return myHandler; + } + + public DomInvocationHandler getHandler() { + return myHandler; + } + + public void setHandler(DomInvocationHandler handler) { + myHandler = handler; + } } diff --git a/xml/dom-impl/src/com/intellij/util/xml/stubs/ElementStub.java b/xml/dom-impl/src/com/intellij/util/xml/stubs/ElementStub.java index 5b25b8528a45..88baba7105f9 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/stubs/ElementStub.java +++ b/xml/dom-impl/src/com/intellij/util/xml/stubs/ElementStub.java @@ -16,7 +16,6 @@ package com.intellij.util.xml.stubs; 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.Nullable; @@ -40,7 +39,7 @@ public class ElementStub extends DomStub { } @Override - public List getChildrenStubs() { + public List getChildrenStubs() { return myChildren; } diff --git a/xml/dom-impl/src/com/intellij/util/xml/stubs/StubParentStrategy.java b/xml/dom-impl/src/com/intellij/util/xml/stubs/StubParentStrategy.java new file mode 100644 index 000000000000..5d0e47bbb75b --- /dev/null +++ b/xml/dom-impl/src/com/intellij/util/xml/stubs/StubParentStrategy.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2012 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.stubs; + +import com.intellij.psi.xml.XmlElement; +import com.intellij.util.xml.impl.DomInvocationHandler; +import com.intellij.util.xml.impl.DomParentStrategy; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Avdeev + * Date: 8/9/12 + */ +public class StubParentStrategy implements DomParentStrategy { + + private final DomStub myStub; + + public StubParentStrategy(DomStub stub) { + myStub = stub; + } + + @Override + public DomInvocationHandler getParentHandler() { + DomStub parentStub = myStub.getParentStub(); + return parentStub == null ? null : parentStub.getHandler(); + } + + @Override + public XmlElement getXmlElement() { + + return null; + } + + @NotNull + @Override + public DomParentStrategy refreshStrategy(DomInvocationHandler handler) { + return this; + } + + @NotNull + @Override + public DomParentStrategy setXmlElement(@NotNull XmlElement element) { + return this; + } + + @NotNull + @Override + public DomParentStrategy clearXmlElement() { + return this; + } + + @Override + public String checkValidity() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/xml/dom-openapi/src/com/intellij/util/xml/EvaluatedXmlNameImpl.java b/xml/dom-openapi/src/com/intellij/util/xml/EvaluatedXmlNameImpl.java index f37eb6482170..c2422f03a1cc 100644 --- a/xml/dom-openapi/src/com/intellij/util/xml/EvaluatedXmlNameImpl.java +++ b/xml/dom-openapi/src/com/intellij/util/xml/EvaluatedXmlNameImpl.java @@ -81,14 +81,14 @@ public class EvaluatedXmlNameImpl implements EvaluatedXmlName { if (myEqualToParent != that.myEqualToParent) return false; if (myNamespaceKey != null ? !myNamespaceKey.equals(that.myNamespaceKey) : that.myNamespaceKey != null) return false; - if (myXmlName != null ? !myXmlName.equals(that.myXmlName) : that.myXmlName != null) return false; + if (!myXmlName.equals(that.myXmlName)) return false; return true; } @Override public int hashCode() { - int result = myXmlName != null ? myXmlName.hashCode() : 0; + int result = myXmlName.hashCode(); result = 31 * result + (myNamespaceKey != null ? myNamespaceKey.hashCode() : 0); result = 31 * result + (myEqualToParent ? 1 : 0); return result; diff --git a/xml/dom-tests/testData/stubs/foo.xml b/xml/dom-tests/testData/stubs/foo.xml index b029af678d96..4fb8f5b5c521 100644 --- a/xml/dom-tests/testData/stubs/foo.xml +++ b/xml/dom-tests/testData/stubs/foo.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/xml/dom-tests/tests/com/intellij/util/xml/stubs/Bar.java b/xml/dom-tests/tests/com/intellij/util/xml/stubs/Bar.java index eaf31f942fc8..4d373e7d6818 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/stubs/Bar.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/stubs/Bar.java @@ -26,5 +26,8 @@ import com.intellij.util.xml.GenericAttributeValue; public interface Bar extends DomElement { @Stubbed - GenericAttributeValue getAttribute(); + GenericAttributeValue getString(); + + @Stubbed + GenericAttributeValue getInt(); } diff --git a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubBuilderTest.java b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubBuilderTest.java index 561a36c27b4a..ef5029260b37 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubBuilderTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubBuilderTest.java @@ -20,7 +20,8 @@ public class DomStubBuilderTest extends DomStubTest { doTest("foo.xml", "File:foo\n" + " Element:foo\n" + " Element:bar\n" + - " Attribute:attribute:xxx\n" + + " Attribute:int:666\n" + + " Attribute:string:xxx\n" + " Element:bar\n"); } diff --git a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubUsingTest.java b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubUsingTest.java index c0795bd3952e..67846437ce33 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubUsingTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubUsingTest.java @@ -15,11 +15,17 @@ */ package com.intellij.util.xml.stubs; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.PsiManagerImpl; +import com.intellij.psi.stubs.ObjectStubTree; +import com.intellij.psi.stubs.StubTreeLoader; import com.intellij.psi.xml.XmlFile; import com.intellij.util.xml.DomFileElement; import com.intellij.util.xml.DomManager; +import java.util.List; + /** * @author Dmitry Avdeev * Date: 8/8/12 @@ -27,9 +33,44 @@ import com.intellij.util.xml.DomManager; public class DomStubUsingTest extends DomStubTest { public void testFoo() throws Exception { - PsiFile file = myFixture.configureByFile("foo.xml"); + + DomFileElement fileElement = prepare("foo.xml"); + PsiFile file; + + file = fileElement.getFile(); + assertFalse(file.getNode().isParsed()); + + Foo foo = fileElement.getRootElement(); + List bars = foo.getBars(); + assertFalse(file.getNode().isParsed()); + + assertEquals(2, bars.size()); + Bar bar = bars.get(0); + String value = bar.getString().getStringValue(); + assertEquals("xxx", value); + + Object o = bar.getString().getValue(); + assertEquals("xxx", o); + + Integer integer = bar.getInt().getValue(); + assertEquals(666, integer.intValue()); + + assertFalse(file.getNode().isParsed()); + } + + private DomFileElement prepare(String path) { + PsiFile file = myFixture.configureByFile(path); + assertFalse(file.getNode().isParsed()); + VirtualFile virtualFile = file.getVirtualFile(); + ObjectStubTree tree = StubTreeLoader.getInstance().readOrBuild(getProject(), virtualFile, file); + assertNotNull(tree); + + ((PsiManagerImpl)getPsiManager()).cleanupForNextTest(); + file = getPsiManager().findFile(virtualFile); + assertFalse(file.getNode().isParsed()); + DomFileElement fileElement = DomManager.getDomManager(getProject()).getFileElement((XmlFile)file, Foo.class); assertNotNull(fileElement); - Foo foo = fileElement.getRootElement(); + return fileElement; } }