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}