001///////////////////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
003// Copyright (C) 2001-2022 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018///////////////////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.xpath;
021
022import java.util.List;
023
024import com.puppycrawl.tools.checkstyle.api.DetailAST;
025import com.puppycrawl.tools.checkstyle.api.TokenTypes;
026import com.puppycrawl.tools.checkstyle.utils.XpathUtil;
027import com.puppycrawl.tools.checkstyle.xpath.iterators.DescendantIterator;
028import net.sf.saxon.Configuration;
029import net.sf.saxon.om.AxisInfo;
030import net.sf.saxon.om.GenericTreeInfo;
031import net.sf.saxon.om.NodeInfo;
032import net.sf.saxon.tree.iter.ArrayIterator;
033import net.sf.saxon.tree.iter.AxisIterator;
034import net.sf.saxon.tree.iter.EmptyIterator;
035import net.sf.saxon.tree.iter.SingleNodeIterator;
036import net.sf.saxon.type.Type;
037
038/**
039 * Represents root node of Xpath-tree.
040 *
041 */
042public class RootNode extends AbstractNode {
043
044    /** Name of the root element. */
045    private static final String ROOT_NAME = "ROOT";
046
047    /** Constant for optimization. */
048    private static final AbstractNode[] EMPTY_ABSTRACT_NODE_ARRAY = new AbstractNode[0];
049
050    /** The ast node. */
051    private final DetailAST detailAst;
052
053    /**
054     * Creates a new {@code RootNode} instance.
055     *
056     * @param detailAst reference to {@code DetailAST}
057     */
058    public RootNode(DetailAST detailAst) {
059        super(new GenericTreeInfo(Configuration.newConfiguration()));
060        this.detailAst = detailAst;
061    }
062
063    /**
064     * Compares current object with specified for order.
065     * Throws {@code UnsupportedOperationException} because functionality not required here.
066     *
067     * @param nodeInfo another {@code NodeInfo} object
068     * @return number representing order of current object to specified one
069     */
070    @Override
071    public int compareOrder(NodeInfo nodeInfo) {
072        throw throwUnsupportedOperationException();
073    }
074
075    /**
076     * Iterates siblings of the current node and
077     * recursively creates new Xpath-nodes.
078     *
079     * @return children list
080     */
081    @Override
082    protected List<AbstractNode> createChildren() {
083        return XpathUtil.createChildren(this, this, detailAst);
084    }
085
086    /**
087     * Determine whether the node has any children.
088     *
089     * @return {@code true} is the node has any children.
090     */
091    @Override
092    public boolean hasChildNodes() {
093        return detailAst != null;
094    }
095
096    /**
097     * Returns attribute value. Throws {@code UnsupportedOperationException} because root node
098     * has no attributes.
099     *
100     * @param namespace namespace
101     * @param localPart actual name of the attribute
102     * @return attribute value
103     */
104    @Override
105    public String getAttributeValue(String namespace, String localPart) {
106        throw throwUnsupportedOperationException();
107    }
108
109    /**
110     * Returns local part.
111     *
112     * @return local part
113     */
114    @Override
115    public String getLocalPart() {
116        return ROOT_NAME;
117    }
118
119    /**
120     * Returns type of the node.
121     *
122     * @return node kind
123     */
124    @Override
125    public int getNodeKind() {
126        return Type.DOCUMENT;
127    }
128
129    /**
130     * Returns parent.
131     *
132     * @return parent
133     */
134    @Override
135    public NodeInfo getParent() {
136        return null;
137    }
138
139    /**
140     * Returns root of the tree.
141     *
142     * @return root of the tree
143     */
144    @Override
145    public NodeInfo getRoot() {
146        return this;
147    }
148
149    /**
150     * Determines axis iteration algorithm. Throws {@code UnsupportedOperationException} in case,
151     * when there is no axis iterator for given axisNumber.
152     *
153     * @param axisNumber element from {@code AxisInfo}
154     * @return {@code AxisIterator} object
155     */
156    @Override
157    public AxisIterator iterateAxis(int axisNumber) {
158        final AxisIterator result;
159        switch (axisNumber) {
160            case AxisInfo.ANCESTOR:
161            case AxisInfo.ATTRIBUTE:
162            case AxisInfo.PARENT:
163            case AxisInfo.FOLLOWING:
164            case AxisInfo.FOLLOWING_SIBLING:
165            case AxisInfo.PRECEDING:
166            case AxisInfo.PRECEDING_SIBLING:
167                result = EmptyIterator.ofNodes();
168                break;
169            case AxisInfo.ANCESTOR_OR_SELF:
170            case AxisInfo.SELF:
171                result = SingleNodeIterator.makeIterator(this);
172                break;
173            case AxisInfo.CHILD:
174                if (hasChildNodes()) {
175                    result = new ArrayIterator.OfNodes<>(
176                            getChildren().toArray(EMPTY_ABSTRACT_NODE_ARRAY));
177                }
178                else {
179                    result = EmptyIterator.ofNodes();
180                }
181                break;
182            case AxisInfo.DESCENDANT:
183                if (hasChildNodes()) {
184                    result = new DescendantIterator(this, DescendantIterator.StartWith.CHILDREN);
185                }
186                else {
187                    result = EmptyIterator.ofNodes();
188                }
189                break;
190            case AxisInfo.DESCENDANT_OR_SELF:
191                result = new DescendantIterator(this, DescendantIterator.StartWith.CURRENT_NODE);
192                break;
193            default:
194                throw throwUnsupportedOperationException();
195        }
196        return result;
197    }
198
199    /**
200     * Returns line number.
201     *
202     * @return line number
203     */
204    @Override
205    public int getLineNumber() {
206        return detailAst.getLineNo();
207    }
208
209    /**
210     * Returns column number.
211     *
212     * @return column number
213     */
214    @Override
215    public int getColumnNumber() {
216        return detailAst.getColumnNo();
217    }
218
219    /**
220     * Getter method for token type.
221     *
222     * @return token type
223     */
224    @Override
225    public int getTokenType() {
226        return TokenTypes.COMPILATION_UNIT;
227    }
228
229    /**
230     * Returns underlying node.
231     *
232     * @return underlying node
233     */
234    @Override
235    public DetailAST getUnderlyingNode() {
236        return detailAst;
237    }
238
239    /**
240     * Getter method for node depth.
241     *
242     * @return always {@code 0}
243     */
244    @Override
245    public int getDepth() {
246        return 0;
247    }
248
249    /**
250     * Returns UnsupportedOperationException exception.
251     *
252     * @return UnsupportedOperationException exception
253     */
254    private static UnsupportedOperationException throwUnsupportedOperationException() {
255        return new UnsupportedOperationException("Operation is not supported");
256    }
257
258}