1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2015 the original author or authors.
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ////////////////////////////////////////////////////////////////////////////////
19 package com.puppycrawl.tools.checkstyle.api;
20
21 import java.util.BitSet;
22
23 import antlr.CommonASTWithHiddenTokens;
24 import antlr.Token;
25 import antlr.collections.AST;
26
27 /**
28 * An extension of the CommonAST that records the line and column
29 * number. The idea was taken from <a target="_top"
30 * href="http://www.jguru.com/jguru/faq/view.jsp?EID=62654">Java Guru
31 * FAQ: How can I include line numbers in automatically generated
32 * ASTs?</a>.
33 * @author Oliver Burn
34 * @author lkuehne
35 * @see <a href="http://www.antlr.org/">ANTLR Website</a>
36 */
37 public final class DetailAST extends CommonASTWithHiddenTokens
38 {
39 /** For Serialisation that will never happen. */
40 private static final long serialVersionUID = -2580884815577559874L;
41
42 /** constant to indicate if not calculated the child count */
43 private static final int NOT_INITIALIZED = Integer.MIN_VALUE;
44
45 /** the line number **/
46 private int lineNo = NOT_INITIALIZED;
47 /** the column number **/
48 private int columnNo = NOT_INITIALIZED;
49
50 /** number of children */
51 private int childCount = NOT_INITIALIZED;
52 /** the parent token */
53 private DetailAST parent;
54 /** previous sibling */
55 private DetailAST previousSibling;
56
57 /**
58 * All token types in this branch.
59 * Token 'x' (where x is an int) is in this branch
60 * if branchTokenTypes.get(x) is true.
61 */
62 private BitSet branchTokenTypes;
63
64 @Override
65 public void initialize(Token tok)
66 {
67 super.initialize(tok);
68 lineNo = tok.getLine();
69 columnNo = tok.getColumn() - 1; // expect columns to start @ 0
70 }
71
72 @Override
73 public void initialize(AST ast)
74 {
75 final DetailAST da = (DetailAST) ast;
76 setText(da.getText());
77 setType(da.getType());
78 lineNo = da.getLineNo();
79 columnNo = da.getColumnNo();
80 hiddenAfter = da.getHiddenAfter();
81 hiddenBefore = da.getHiddenBefore();
82 }
83
84 @Override
85 public void setFirstChild(AST ast)
86 {
87 childCount = NOT_INITIALIZED;
88 super.setFirstChild(ast);
89 if (ast != null) {
90 ((DetailAST) ast).setParent(this);
91 }
92 }
93
94 @Override
95 public void setNextSibling(AST ast)
96 {
97 super.setNextSibling(ast);
98 if (ast != null && parent != null) {
99 ((DetailAST) ast).setParent(parent);
100 }
101 if (ast != null) {
102 ((DetailAST) ast).setPreviousSibling(this);
103 }
104 }
105
106 /**
107 * Add previous sibling.
108 * @param ast
109 * DetailAST object.
110 */
111 public void addPreviousSibling(DetailAST ast)
112 {
113 if (ast != null) {
114 ast.setParent(parent);
115 final DetailAST previousSibling = this.getPreviousSibling();
116
117 if (previousSibling != null) {
118 ast.setPreviousSibling(previousSibling);
119 previousSibling.setNextSibling(ast);
120 }
121 else if (parent != null) {
122 parent.setFirstChild(ast);
123 }
124
125 ast.setNextSibling(this);
126 this.setPreviousSibling(ast);
127 }
128 }
129
130 /**
131 * Add next sibling.
132 * @param ast
133 * DetailAST object.
134 */
135 public void addNextSibling(DetailAST ast)
136 {
137 if (ast != null) {
138 ast.setParent(parent);
139 final DetailAST nextSibling = this.getNextSibling();
140
141 if (nextSibling != null) {
142 ast.setNextSibling(nextSibling);
143 nextSibling.setPreviousSibling(ast);
144 }
145
146 ast.setPreviousSibling(this);
147 this.setNextSibling(ast);
148 }
149 }
150
151 /**
152 * Sets previous sibling.
153 * @param ast a previous sibling
154 */
155 void setPreviousSibling(DetailAST ast)
156 {
157 previousSibling = ast;
158 }
159
160 @Override
161 public void addChild(AST ast)
162 {
163 super.addChild(ast);
164 if (ast != null) {
165 ((DetailAST) ast).setParent(this);
166 getFirstChild().setParent(this);
167 }
168 }
169
170 /**
171 * Returns the number of child nodes one level below this node. That is is
172 * does not recurse down the tree.
173 * @return the number of child nodes
174 */
175 public int getChildCount()
176 {
177 // lazy init
178 if (childCount == NOT_INITIALIZED) {
179 childCount = 0;
180 AST child = getFirstChild();
181
182 while (child != null) {
183 childCount += 1;
184 child = child.getNextSibling();
185 }
186 }
187 return childCount;
188 }
189
190 /**
191 * Set the parent token.
192 * @param parent the parent token
193 */
194 // TODO: should be private but that breaks the DetailASTTest
195 // until we manage parent in DetailAST instead of externally
196 void setParent(DetailAST parent)
197 {
198 // TODO: Check visibility, could be private
199 // if set in setFirstChild() and friends
200 this.parent = parent;
201 final DetailAST nextSibling = getNextSibling();
202 if (nextSibling != null) {
203 nextSibling.setParent(parent);
204 nextSibling.setPreviousSibling(this);
205 }
206 }
207
208 /**
209 * Returns the parent token.
210 * @return the parent token
211 */
212 public DetailAST getParent()
213 {
214 return parent;
215 }
216
217 /** @return the line number **/
218 public int getLineNo()
219 {
220 if (lineNo == NOT_INITIALIZED) {
221 // an inner AST that has been initialized
222 // with initialize(String text)
223 DetailAST child = getFirstChild();
224 while (child != null) {
225 // comment node can't be start of any java statement/definition
226 if (TokenTypes.isCommentType(child.getType())) {
227 child = child.getNextSibling();
228 }
229 else {
230 return child.getLineNo();
231 }
232 }
233
234 DetailAST sibling = getNextSibling();
235 while (sibling != null) {
236 // comment node can't be start of any java statement/definition
237 if (TokenTypes.isCommentType(sibling.getType())) {
238 sibling = sibling.getNextSibling();
239 }
240 else {
241 return sibling.getLineNo();
242 }
243 }
244 }
245 return lineNo;
246 }
247
248 /**
249 * Set line number.
250 * @param lineNo
251 * line number.
252 */
253 public void setLineNo(int lineNo)
254 {
255 this.lineNo = lineNo;
256 }
257
258 /** @return the column number **/
259 public int getColumnNo()
260 {
261 if (columnNo == NOT_INITIALIZED) {
262 // an inner AST that has been initialized
263 // with initialize(String text)
264 DetailAST child = getFirstChild();
265 while (child != null) {
266 // comment node can't be start of any java statement/definition
267 if (TokenTypes.isCommentType(child.getType())) {
268 child = child.getNextSibling();
269 }
270 else {
271 return child.getColumnNo();
272 }
273 }
274
275 DetailAST sibling = getNextSibling();
276 while (sibling != null) {
277 // comment node can't be start of any java statement/definition
278 if (TokenTypes.isCommentType(sibling.getType())) {
279 sibling = sibling.getNextSibling();
280 }
281 else {
282 return sibling.getColumnNo();
283 }
284 }
285 }
286 return columnNo;
287 }
288
289 /**
290 * Set column number.
291 * @param columnNo
292 * column number.
293 */
294 public void setColumnNo(int columnNo)
295 {
296 this.columnNo = columnNo;
297 }
298
299 /** @return the last child node */
300 public DetailAST getLastChild()
301 {
302 DetailAST ast = getFirstChild();
303 while (ast != null && ast.getNextSibling() != null) {
304 ast = ast.getNextSibling();
305 }
306 return ast;
307 }
308
309 /**
310 * @return the token types that occur in the branch as a sorted set.
311 */
312 private BitSet getBranchTokenTypes()
313 {
314 // lazy init
315 if (branchTokenTypes == null) {
316
317 branchTokenTypes = new BitSet();
318 branchTokenTypes.set(getType());
319
320 // add union of all childs
321 DetailAST child = getFirstChild();
322 while (child != null) {
323 final BitSet childTypes = child.getBranchTokenTypes();
324 branchTokenTypes.or(childTypes);
325
326 child = child.getNextSibling();
327 }
328 }
329 return branchTokenTypes;
330 }
331
332 /**
333 * Checks if this branch of the parse tree contains a token
334 * of the provided type.
335 * @param type a TokenType
336 * @return true if and only if this branch (including this node)
337 * contains a token of type <code>type</code>.
338 */
339 public boolean branchContains(int type)
340 {
341 return getBranchTokenTypes().get(type);
342 }
343
344 /**
345 * Returns the number of direct child tokens that have the specified type.
346 * @param type the token type to match
347 * @return the number of matching token
348 */
349 public int getChildCount(int type)
350 {
351 int count = 0;
352 for (AST i = getFirstChild(); i != null; i = i.getNextSibling()) {
353 if (i.getType() == type) {
354 count++;
355 }
356 }
357 return count;
358 }
359
360 /**
361 * Returns the previous sibling or null if no such sibling exists.
362 * @return the previous sibling or null if no such sibling exists.
363 */
364 public DetailAST getPreviousSibling()
365 {
366 return previousSibling;
367 }
368
369 /**
370 * Returns the first child token that makes a specified type.
371 * @param type the token type to match
372 * @return the matching token, or null if no match
373 */
374 public DetailAST findFirstToken(int type)
375 {
376 DetailAST retVal = null;
377 for (DetailAST i = getFirstChild(); i != null; i = i.getNextSibling()) {
378 if (i.getType() == type) {
379 retVal = i;
380 break;
381 }
382 }
383 return retVal;
384 }
385
386 @Override
387 public String toString()
388 {
389 return super.toString() + "[" + getLineNo() + "x" + getColumnNo() + "]";
390 }
391
392 @Override
393 public DetailAST getNextSibling()
394 {
395 return (DetailAST) super.getNextSibling();
396 }
397
398 @Override
399 public DetailAST getFirstChild()
400 {
401 return (DetailAST) super.getFirstChild();
402 }
403
404 }