001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2014 Oliver Burn 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//////////////////////////////////////////////////////////////////////////////// 019package com.puppycrawl.tools.checkstyle.api; 020 021import java.util.BitSet; 022 023import antlr.CommonAST; 024import antlr.Token; 025import antlr.collections.AST; 026 027/** 028 * An extension of the CommonAST that records the line and column 029 * number. The idea was taken from <a target="_top" 030 * href="http://www.jguru.com/jguru/faq/view.jsp?EID=62654">Java Guru 031 * FAQ: How can I include line numbers in automatically generated 032 * ASTs?</a>. 033 * @author Oliver Burn 034 * @author lkuehne 035 * @version 1.0 036 * @see <a href="http://www.antlr.org/">ANTLR Website</a> 037 */ 038public final class DetailAST extends CommonAST 039{ 040 /** For Serialisation that will never happen. */ 041 private static final long serialVersionUID = -2580884815577559874L; 042 043 /** constant to indicate if not calculated the child count */ 044 private static final int NOT_INITIALIZED = Integer.MIN_VALUE; 045 046 /** the line number **/ 047 private int mLineNo = NOT_INITIALIZED; 048 /** the column number **/ 049 private int mColumnNo = NOT_INITIALIZED; 050 051 /** number of children */ 052 private int mChildCount = NOT_INITIALIZED; 053 /** the parent token */ 054 private DetailAST mParent; 055 /** previous sibling */ 056 private DetailAST mPreviousSibling; 057 058 /** 059 * All token types in this branch. 060 * Token 'x' (where x is an int) is in this branch 061 * if mBranchTokenTypes.get(x) is true. 062 */ 063 private BitSet mBranchTokenTypes; 064 065 @Override 066 public void initialize(Token aTok) 067 { 068 super.initialize(aTok); 069 mLineNo = aTok.getLine(); 070 mColumnNo = aTok.getColumn() - 1; // expect columns to start @ 0 071 } 072 073 @Override 074 public void initialize(AST aAST) 075 { 076 final DetailAST da = (DetailAST) aAST; 077 setText(da.getText()); 078 setType(da.getType()); 079 mLineNo = da.getLineNo(); 080 mColumnNo = da.getColumnNo(); 081 } 082 083 @Override 084 public void setFirstChild(AST aAST) 085 { 086 mChildCount = NOT_INITIALIZED; 087 super.setFirstChild(aAST); 088 if (aAST != null) { 089 ((DetailAST) aAST).setParent(this); 090 } 091 } 092 093 @Override 094 public void setNextSibling(AST aAST) 095 { 096 super.setNextSibling(aAST); 097 if ((aAST != null) && (mParent != null)) { 098 ((DetailAST) aAST).setParent(mParent); 099 } 100 if (aAST != null) { 101 ((DetailAST) aAST).setPreviousSibling(this); 102 } 103 } 104 105 /** 106 * Sets previous sibling. 107 * @param aAST a previous sibling 108 */ 109 void setPreviousSibling(DetailAST aAST) 110 { 111 mPreviousSibling = aAST; 112 } 113 114 @Override 115 public void addChild(AST aAST) 116 { 117 super.addChild(aAST); 118 if (aAST != null) { 119 ((DetailAST) aAST).setParent(this); 120 (getFirstChild()).setParent(this); 121 } 122 } 123 124 /** 125 * Returns the number of child nodes one level below this node. That is is 126 * does not recurse down the tree. 127 * @return the number of child nodes 128 */ 129 public int getChildCount() 130 { 131 // lazy init 132 if (mChildCount == NOT_INITIALIZED) { 133 mChildCount = 0; 134 AST child = getFirstChild(); 135 136 while (child != null) { 137 mChildCount += 1; 138 child = child.getNextSibling(); 139 } 140 } 141 return mChildCount; 142 } 143 144 /** 145 * Set the parent token. 146 * @param aParent the parent token 147 */ 148 // TODO: should be private but that breaks the DetailASTTest 149 // until we manage parent in DetailAST instead of externally 150 void setParent(DetailAST aParent) 151 { 152 // TODO: Check visibility, could be private 153 // if set in setFirstChild() and friends 154 mParent = aParent; 155 final DetailAST nextSibling = getNextSibling(); 156 if (nextSibling != null) { 157 nextSibling.setParent(aParent); 158 nextSibling.setPreviousSibling(this); 159 } 160 } 161 162 /** 163 * Returns the parent token. 164 * @return the parent token 165 */ 166 public DetailAST getParent() 167 { 168 return mParent; 169 } 170 171 /** @return the line number **/ 172 public int getLineNo() 173 { 174 if (mLineNo == NOT_INITIALIZED) { 175 // an inner AST that has been initialized 176 // with initialize(String text) 177 final DetailAST child = getFirstChild(); 178 final DetailAST sibling = getNextSibling(); 179 if (child != null) { 180 return child.getLineNo(); 181 } 182 else if (sibling != null) { 183 return sibling.getLineNo(); 184 } 185 } 186 return mLineNo; 187 } 188 189 /** @return the column number **/ 190 public int getColumnNo() 191 { 192 if (mColumnNo == NOT_INITIALIZED) { 193 // an inner AST that has been initialized 194 // with initialize(String text) 195 final DetailAST child = getFirstChild(); 196 final DetailAST sibling = getNextSibling(); 197 if (child != null) { 198 return child.getColumnNo(); 199 } 200 else if (sibling != null) { 201 return sibling.getColumnNo(); 202 } 203 } 204 return mColumnNo; 205 } 206 207 /** @return the last child node */ 208 public DetailAST getLastChild() 209 { 210 DetailAST ast = getFirstChild(); 211 while ((ast != null) && (ast.getNextSibling() != null)) { 212 ast = ast.getNextSibling(); 213 } 214 return ast; 215 } 216 217 /** 218 * @return the token types that occur in the branch as a sorted set. 219 */ 220 private BitSet getBranchTokenTypes() 221 { 222 // lazy init 223 if (mBranchTokenTypes == null) { 224 225 mBranchTokenTypes = new BitSet(); 226 mBranchTokenTypes.set(getType()); 227 228 // add union of all childs 229 DetailAST child = getFirstChild(); 230 while (child != null) { 231 final BitSet childTypes = child.getBranchTokenTypes(); 232 mBranchTokenTypes.or(childTypes); 233 234 child = child.getNextSibling(); 235 } 236 } 237 return mBranchTokenTypes; 238 } 239 240 /** 241 * Checks if this branch of the parse tree contains a token 242 * of the provided type. 243 * @param aType a TokenType 244 * @return true if and only if this branch (including this node) 245 * contains a token of type <code>aType</code>. 246 */ 247 public boolean branchContains(int aType) 248 { 249 return getBranchTokenTypes().get(aType); 250 } 251 252 /** 253 * Returns the number of direct child tokens that have the specified type. 254 * @param aType the token type to match 255 * @return the number of matching token 256 */ 257 public int getChildCount(int aType) 258 { 259 int count = 0; 260 for (AST i = getFirstChild(); i != null; i = i.getNextSibling()) { 261 if (i.getType() == aType) { 262 count++; 263 } 264 } 265 return count; 266 } 267 268 /** 269 * Returns the previous sibling or null if no such sibling exists. 270 * @return the previous sibling or null if no such sibling exists. 271 */ 272 public DetailAST getPreviousSibling() 273 { 274 return mPreviousSibling; 275 } 276 277 /** 278 * Returns the first child token that makes a specified type. 279 * @param aType the token type to match 280 * @return the matching token, or null if no match 281 */ 282 public DetailAST findFirstToken(int aType) 283 { 284 DetailAST retVal = null; 285 for (DetailAST i = getFirstChild(); i != null; i = i.getNextSibling()) { 286 if (i.getType() == aType) { 287 retVal = i; 288 break; 289 } 290 } 291 return retVal; 292 } 293 294 @Override 295 public String toString() 296 { 297 return super.toString() + "[" + getLineNo() + "x" + getColumnNo() + "]"; 298 } 299 300 @Override 301 public DetailAST getNextSibling() 302 { 303 return (DetailAST) super.getNextSibling(); 304 } 305 306 @Override 307 public DetailAST getFirstChild() 308 { 309 return (DetailAST) super.getFirstChild(); 310 } 311}