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