Source code: com/puppycrawl/tools/checkstyle/checks/usage/transmogrify/SymTabAST.java
1
2 // Transmogrify License
3 //
4 // Copyright (c) 2001, ThoughtWorks, Inc.
5 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
8 // are met:
9 // - Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // - Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // Neither the name of the ThoughtWorks, Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from this
16 // software without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 package com.puppycrawl.tools.checkstyle.checks.usage.transmogrify;
30
31 import java.io.File;
32
33 import antlr.collections.AST;
34
35 import com.puppycrawl.tools.checkstyle.api.DetailAST;
36 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
37
38
39
40 /**
41 * an extension of <code>antlr.CommonAST</code> that includes
42 * extra information about the AST's location. This information
43 * is the file and line number where the AST was created.
44 *
45 * To use this AST node in your tree structure, assuming your
46 * antlr.TreeParser is called parser, use
47 *
48 * parser.setASTNOdeCLass(SymTabAST.class.getName());
49 *
50 * make sure you also call setTokenObjectClass for the lexer as well
51 *
52 *
53 * @see SymTabToken
54 */
55 //TODO: Should be an adapter of DetailAST
56
57 public class SymTabAST
58 extends antlr.CommonASTWithHiddenTokens
59 {
60 private Scope _scope;
61 private IDefinition _definition = null;
62 private boolean _isMeaningful = true;
63
64 private File _file;
65 private int _line;
66 private int _column;
67
68 // parent is not used by Checkstyle
69 // private SymTabAST parent;
70
71 private Span _span;
72
73 /** original syntax tree node */
74 private DetailAST detailNode;
75
76 // /**
77 // * gets parent of this node
78 // * @return <code>SymTabAST</code>
79 // */
80 // public SymTabAST getParent() {
81 // return parent;
82 // }
83
84 // /**
85 // * gets previous sibling of this node
86 // * @return <code>SymTabAST</code>
87 // */
88 // public SymTabAST getPreviousSibling() {
89 // return prevSibling;
90 // }
91
92 /**
93 * sets parent of this node
94 * @param parent
95 * @return <code>void</code>
96 */
97 public void setParent(SymTabAST parent) {
98 //parent is not used by Checkstyle
99 // this.parent = parent;
100 }
101
102 /**
103 * gets the scope of this node
104 * @return <code>Scope</code>
105 */
106 public Scope getScope() {
107 return _scope;
108 }
109
110 /**
111 * sets the scope of this node
112 * @param scope
113 * @return <code>void</code>
114 */
115 public void setScope(Scope scope) {
116 _scope = scope;
117 }
118
119 /**
120 * sets <code>Definition</code> for this node
121 * @param definition
122 * @param scope
123 * @return <code>void</code>
124 * @see #setDefinition(IDefinition, Scope, boolean)
125 */
126 public void setDefinition(IDefinition definition, Scope scope) {
127 setDefinition(definition, scope, true);
128 }
129
130 /**
131 * sets <code>Definition</code> for this node and adds <code>Reference</code>
132 * to the <code>_definition</code> and <code>scope</code>
133 * @param definition
134 * @param scope
135 * @param createReference
136 * @return <code>void</code>
137 * @see net.sourceforge.transmogrify.symtab.Reference
138 */
139 public void setDefinition(
140 IDefinition definition,
141 Scope scope,
142 boolean createReference) {
143 _definition = definition;
144 Reference reference = new Reference(this);
145 if (scope != null) {
146 scope.addReferenceInScope(reference);
147 }
148
149 if (definition.isSourced() && createReference) {
150 _definition.addReference(reference);
151 }
152 }
153
154 /**
155 * gets <code>_definitin</code>
156 * @return <code>IDefinition</code>
157 */
158 public IDefinition getDefinition() {
159 return _definition;
160 }
161
162 /**
163 * tests if this node is meaningful or should be ignored
164 * @return <code>boolean</code>
165 */
166 public boolean isMeaningful() {
167 return _isMeaningful;
168 }
169
170 /**
171 * sets <code>_isMeaningful</code> member
172 * @param isMeaningful
173 * @return <code>void</code>
174 */
175 public void setMeaningfulness(boolean isMeaningful) {
176 _isMeaningful = isMeaningful;
177 }
178
179 /**
180 * sets meaningfulness for this node and its children
181 * @return <code>void</code>
182 * @see #setMeaningfulness(boolean)
183 */
184 public void ignoreChildren() {
185 if (getType() == TokenTypes.IDENT) {
186 setMeaningfulness(false);
187 }
188 SymTabAST child = (SymTabAST) getFirstChild();
189 while (child != null) {
190 child.ignoreChildren();
191 child = (SymTabAST) child.getNextSibling();
192 }
193 }
194
195 /**
196 * sets file where this node belong to
197 * @param file
198 * @return <code>void</code>
199 */
200 public void setFile(File file) {
201 _file = file;
202 }
203
204 /**
205 * finishes process for adding node to its parent
206 * @param file file where this node belongs to
207 * @param parent parent of this node
208 * @param previousSibling previous sibling of this node
209 * @return <code>Span</code> the span of this node
210 * @see #setFile(File)
211 * @see #setParent(SymTabAST)
212 * @see #setPreviousSibling(SymTabAST)
213 * @see #finishChildren(File)
214 * @see #setSpan(Span)
215 */
216 public Span finishDefinition(
217 File file,
218 SymTabAST parent) {
219 setFile(file);
220 setParent(parent);
221
222 Span result = finishChildren(file);
223
224 if (getLineNo() != 0) {
225 result.compose(
226 new Span(
227 getLineNo(),
228 getColumnNo(),
229 getLineNo(),
230 getColumnNo()
231 + ((getText() == null) ? 0 : getText().length() - 1)));
232 }
233
234 setSpan(result);
235 return result;
236 }
237
238 /**
239 * finishes children of this node definition process
240 * @param file file where this node belongs to
241 * @return <code>Span</code>
242 * @see #finishDefinition(File, SymTabAST, SymTabAST)
243 */
244 public Span finishChildren(File file) {
245 Span result = null;
246 SymTabAST previousSibling = null;
247 SymTabAST current = (SymTabAST) getFirstChild();
248
249 if (current == null) {
250 result = getSpan();
251 }
252 else {
253 while (current != null) {
254 Span childSpan =
255 current.finishDefinition(file, this);
256
257 if (childSpan != null) {
258 if (result == null) {
259 result = new Span(childSpan);
260 }
261 else {
262 result.compose(childSpan);
263 }
264 }
265
266 SymTabAST temp = current;
267 current = (SymTabAST) current.getNextSibling();
268 previousSibling = temp;
269 }
270 }
271
272 return result;
273 }
274
275 /**
276 * gets file where this node belongs to
277 * @return <code>File</code>
278 */
279 public File getFile() {
280 return _file;
281 }
282
283 /**
284 * sets the line where this node reside
285 * @return <code>void</code>
286 */
287 public void setLine(int line) {
288 _line = line;
289 }
290
291 /**
292 * gets the line where this node reside
293 * @return <code>int</code>
294 */
295 public int getLineNo() {
296 return _line;
297 }
298
299 /**
300 * sets the column where this node reside
301 * @param column
302 */
303 public void setColumn(int column) {
304 _column = column;
305 }
306
307 /**
308 * gets the column where this node reside
309 * @return <code>int</code>
310 */
311 public int getColumnNo() {
312 return _column;
313 }
314
315 /**
316 * gets the definition name of this node
317 * @return <code>String</code>
318 * @see net.sourceforge.transmogrify.symtab.IDefinition
319 */
320 public String getName() {
321 String result = null;
322 if (_definition != null) {
323 result = _definition.getName();
324 }
325
326 return result;
327 }
328
329 /**
330 * makes a new copy of the current <code>SymTabAST</code>. Uses the
331 * initialize(AST t) method to copy properties for each cloned node.
332 *
333 * @return <code>SymTabAST</code> a full tree copy of the current tree
334 */
335 private SymTabAST treeCopy()
336 {
337 SymTabAST copyOfThis = SymTabASTFactory.create(getType(), getText());
338 copyOfThis.initialize(this);
339
340 if (getFirstChild() != null) {
341 copyOfThis.setFirstChild(((SymTabAST) getFirstChild()).treeCopy());
342 }
343
344 if (getNextSibling() != null) {
345 copyOfThis.setNextSibling(
346 ((SymTabAST) getNextSibling()).treeCopy());
347 }
348
349 return copyOfThis;
350 }
351
352 /**
353 * prints the line, column and file for this node for debugging purpose
354 * @return <code>String</code>
355 */
356 public String toString() {
357 //StringBuffer resultBuffer = new StringBuffer(super.toString());
358 StringBuffer resultBuffer = new StringBuffer(prefixString(true));
359 resultBuffer.append("[" + getLineNo() + "," + getColumnNo() + "]");
360 //if ( getSpan() != null ) {
361 // resultBuffer.append( " spans " + getSpan() );
362 //}
363 resultBuffer.append(" in " + getFile());
364 //resultBuffer.append(" type: " + getType());
365 return resultBuffer.toString();
366 }
367
368 public String prefixString(boolean verboseStringConversion) {
369 StringBuffer b = new StringBuffer();
370
371 try {
372 final String name = TokenTypes.getTokenName(getType());
373 // if verbose and type name not same as text (keyword probably)
374 if (verboseStringConversion && !getText().equalsIgnoreCase(name)) {
375 b.append('[');
376 b.append(getText());
377 b.append(",<");
378 b.append(name);
379 b.append(">]");
380 return b.toString();
381 }
382 }
383 catch (Exception ex) {
384 ;
385 }
386 return getText();
387 }
388
389 /**
390 * gets <code>Span</code> of this node
391 * @return <code>Span</code>
392 */
393 public Span getSpan() {
394 if ((_span == null)) {
395 int endColumn = getColumnNo() + 1;
396 final String text = getText();
397 if (text != null) {
398 endColumn += text.length() - 1;
399 }
400 _span = new Span(getLineNo(), getColumnNo() + 1, getLineNo(), endColumn);
401 }
402 return _span;
403 }
404
405 /**
406 * sets <code>Span</code> for this node
407 * @param span
408 * @return <code>void</code>
409 */
410 public void setSpan(Span span) {
411 _span = span;
412 }
413
414 // not used by Checkstyle
415 // /**
416 // * tests if this node is inside the span
417 // * @param line
418 // * @param column
419 // * @return <code>boolean</code> <code>true</code> if this node is within the span
420 // * <code>false</code> otherwise
421 // */
422 // public boolean contains(int line, int column) {
423 // return getSpan().contains(line, column);
424 // }
425
426 /**
427 * gets enclosing node for this node based on line and column
428 * @param line
429 * @param column
430 * @return <code>SymTabAST</code>
431 * @see #getSpan()
432 */
433 public SymTabAST getEnclosingNode(int line, int column) {
434 SymTabAST result = null;
435
436 if ((getSpan() != null) && (getSpan().contains(line, column))) {
437 SymTabAST child = (SymTabAST) getFirstChild();
438 while (child != null && result == null) {
439 result = child.getEnclosingNode(line, column);
440 child = (SymTabAST) child.getNextSibling();
441 }
442
443 // if none of the children contain it, I'm the best node
444 if (result == null) {
445 result = this;
446 }
447
448 }
449 return result;
450 }
451
452 public AST getFirstChild()
453 {
454 if (super.getFirstChild() == null) {
455 DetailAST childDetailAST = null;
456 final DetailAST detailAST = getDetailNode();
457 if (detailAST != null) {
458 childDetailAST = (DetailAST) detailAST.getFirstChild();
459 if (childDetailAST != null) {
460 final SymTabAST child =
461 SymTabASTFactory.create(childDetailAST);
462 setFirstChild(child);
463 child.setParent(this);
464 child.setFile(getFile());
465 }
466 }
467 }
468 return super.getFirstChild();
469 }
470
471 public AST getNextSibling()
472 {
473 if (super.getNextSibling() == null) {
474 DetailAST siblingDetailAST = null;
475 final DetailAST detailAST = getDetailNode();
476 if (detailAST != null) {
477 siblingDetailAST = (DetailAST) detailAST.getNextSibling();
478 if (siblingDetailAST != null) {
479 final SymTabAST sibling =
480 SymTabASTFactory.create(siblingDetailAST);
481 setNextSibling(sibling);
482 // sibling.setParent(this.getParent());
483 sibling.setFile(getFile());
484 }
485 }
486 }
487 return super.getNextSibling();
488 }
489
490
491 /**
492 * initialized this node with input node
493 * @param aAST the node to initialize from. Must be a
494 * <code>DetailAST</code> object.
495 */
496 public void initialize(AST aAST)
497 {
498 if (aAST != null) {
499 super.initialize(aAST);
500 final DetailAST detailAST = (DetailAST) aAST;
501 setDetailNode(detailAST);
502 _column = detailAST.getColumnNo() + 1;
503 _line = detailAST.getLineNo();
504 }
505 }
506
507 /**
508 * Gets first occurence of the child node with a certain type
509 * @param type
510 * @return <code>SymTabAST</code>
511 * @see #getType()
512 */
513 public SymTabAST findFirstToken(int type) {
514 SymTabAST result = null;
515
516 AST sibling = getFirstChild();
517 while (sibling != null) {
518 if (sibling.getType() == type) {
519 result = (SymTabAST) sibling;
520 break;
521 }
522 sibling = sibling.getNextSibling();
523 }
524
525 return result;
526 }
527
528 // not used by Checkstyle
529 // /**
530 // * adds a node to the last position of this node children
531 // * @param child
532 // * @return <code>void</code>
533 // */
534 // public void addChild(SymTabAST child)
535 // {
536 // SymTabAST lastChild = (SymTabAST) getFirstChild();
537 // if (lastChild == null) {
538 // setFirstChild(child);
539 // child.setParent(this);
540 // child.setNextSibling(null);
541 // }
542 // else {
543 // while (lastChild.getNextSibling() != null) {
544 // lastChild = (SymTabAST) lastChild.getNextSibling();
545 // }
546 // lastChild.setNextSibling(child);
547 // child.setNextSibling(null);
548 // child.setParent(this);
549 // }
550 // }
551
552 /**
553 * Gets Iterator for this node
554 * @return <code>SymTabASTIterator</code>
555 */
556 public SymTabASTIterator getChildren()
557 {
558 return new SymTabASTIterator(this);
559 }
560
561 /**
562 * Returns the DetailAST associated with this node.
563 * @return the DetailAST associated with this node.
564 */
565 public DetailAST getDetailNode()
566 {
567 return detailNode;
568 }
569
570 /**
571 * Sets the DetailAST associated with this node.
572 * @param aDetailAST the DetailAST associated with this node.
573 */
574 public void setDetailNode(DetailAST aDetailAST)
575 {
576 detailNode = aDetailAST;
577 ASTManager.getInstance().put(aDetailAST, this);
578 }
579
580 }