Node.java revision 9528039468accca4734ee3b35670bd1d52369e4c
1/*
2 * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
3 * Copyright (C) 2011, 2013-2015 The JavaParser Team.
4 *
5 * This file is part of JavaParser.
6 *
7 * JavaParser can be used either under the terms of
8 * a) the GNU Lesser General Public License as published by
9 *     the Free Software Foundation, either version 3 of the License, or
10 *     (at your option) any later version.
11 * b) the terms of the Apache License
12 *
13 * You should have received a copy of both licenses in LICENCE.LGPL and
14 * LICENCE.APACHE. Please refer to those files for details.
15 *
16 * JavaParser is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 */
21
22package com.github.javaparser.ast;
23
24import java.util.Iterator;
25import java.util.LinkedList;
26import java.util.List;
27
28import com.github.javaparser.ast.comments.Comment;
29import com.github.javaparser.ast.visitor.*;
30
31/**
32 * Abstract class for all nodes of the AST.
33 *
34 * Each Node can have one associated comment which describe it and
35 * a number of "orphan comments" which it contains but are not specifically
36 * associated to any element.
37 *
38 * @author Julio Vilmar Gesser
39 */
40public abstract class Node implements Cloneable {
41
42    private int beginLine;
43
44    private int beginColumn;
45
46    private int endLine;
47
48    private int endColumn;
49
50    private Node parentNode;
51
52    private List<Node> childrenNodes = new LinkedList<Node>();
53    private List<Comment> orphanComments = new LinkedList<Comment>();
54
55    /**
56     * This attribute can store additional information from semantic analysis.
57     */
58    private Object data;
59
60    private Comment comment;
61
62    public Node() {
63    }
64
65    public Node(final int beginLine, final int beginColumn, final int endLine, final int endColumn) {
66        this.beginLine = beginLine;
67        this.beginColumn = beginColumn;
68        this.endLine = endLine;
69        this.endColumn = endColumn;
70    }
71
72    /**
73     * Accept method for visitor support.
74     *
75     * @param <R>
76     *            the type the return value of the visitor
77     * @param <A>
78     *            the type the argument passed to the visitor
79     * @param v
80     *            the visitor implementation
81     * @param arg
82     *            the argument passed to the visitor
83     * @return the result of the visit
84     */
85    public abstract <R, A> R accept(GenericVisitor<R, A> v, A arg);
86
87    /**
88     * Accept method for visitor support.
89     *
90     * @param <A>
91     *            the type the argument passed for the visitor
92     * @param v
93     *            the visitor implementation
94     * @param arg
95     *            any value relevant for the visitor
96     */
97    public abstract <A> void accept(VoidVisitor<A> v, A arg);
98
99    /**
100     * Return the begin column of this node.
101     *
102     * @return the begin column of this node
103     */
104    public final int getBeginColumn() {
105        return beginColumn;
106    }
107
108    /**
109     * Return the begin line of this node.
110     *
111     * @return the begin line of this node
112     */
113    public final int getBeginLine() {
114        return beginLine;
115    }
116
117    /**
118     * This is a comment associated with this node.
119     *
120     * @return comment property
121     */
122    public final Comment getComment() {
123        return comment;
124    }
125
126    /**
127     * Use this to retrieve additional information associated to this node.
128     *
129     * @return data property
130     */
131    public final Object getData() {
132        return data;
133    }
134
135    /**
136     * Return the end column of this node.
137     *
138     * @return the end column of this node
139     */
140    public final int getEndColumn() {
141        return endColumn;
142    }
143
144    /**
145     * Return the end line of this node.
146     *
147     * @return the end line of this node
148     */
149    public final int getEndLine() {
150        return endLine;
151    }
152
153    /**
154     * Sets the begin column of this node.
155     *
156     * @param beginColumn
157     *            the begin column of this node
158     */
159    public final void setBeginColumn(final int beginColumn) {
160        this.beginColumn = beginColumn;
161    }
162
163    /**
164     * Sets the begin line of this node.
165     *
166     * @param beginLine
167     *            the begin line of this node
168     */
169    public final void setBeginLine(final int beginLine) {
170        this.beginLine = beginLine;
171    }
172
173    /**
174     * Use this to store additional information to this node.
175     *
176     * @param comment to be set
177     */
178    public final void setComment(final Comment comment) {
179        if (comment != null && (this instanceof Comment)) {
180            throw new RuntimeException("A comment can not be commented");
181        }
182        if (this.comment != null)
183        {
184            this.comment.setCommentedNode(null);
185        }
186        this.comment = comment;
187        if (comment != null) {
188            this.comment.setCommentedNode(this);
189        }
190    }
191
192    /**
193     * Use this to store additional information to this node.
194     *
195     * @param data to be set
196     */
197    public final void setData(final Object data) {
198        this.data = data;
199    }
200
201    /**
202     * Sets the end column of this node.
203     *
204     * @param endColumn
205     *            the end column of this node
206     */
207    public final void setEndColumn(final int endColumn) {
208        this.endColumn = endColumn;
209    }
210
211    /**
212     * Sets the end line of this node.
213     *
214     * @param endLine
215     *            the end line of this node
216     */
217    public final void setEndLine(final int endLine) {
218        this.endLine = endLine;
219    }
220
221    /**
222     * Return the String representation of this node.
223     *
224     * @return the String representation of this node
225     */
226    @Override
227    public final String toString() {
228        final DumpVisitor visitor = new DumpVisitor();
229        accept(visitor, null);
230        return visitor.getSource();
231    }
232
233    public final String toStringWithoutComments() {
234        final DumpVisitor visitor = new DumpVisitor(false);
235        accept(visitor, null);
236        return visitor.getSource();
237    }
238
239    @Override
240    public final int hashCode() {
241        return toString().hashCode();
242    }
243
244    @Override
245    public boolean equals(final Object obj) {
246        if (obj == null || !(obj instanceof Node)) {
247            return false;
248        }
249        return EqualsVisitor.equals(this, (Node) obj);
250    }
251
252    @Override
253    public Node clone() {
254        return this.accept(new CloneVisitor(), null);
255    }
256
257    public Node getParentNode() {
258        return parentNode;
259    }
260
261    public List<Node> getChildrenNodes() {
262        return childrenNodes;
263    }
264
265    public boolean contains(Node other) {
266        if (getBeginLine() > other.getBeginLine()) return false;
267        if (getBeginLine() == other.getBeginLine() && getBeginColumn() > other.getBeginColumn()) return false;
268        if (getEndLine() < other.getEndLine()) return false;
269        if (getEndLine() == other.getEndLine() && getEndColumn() < other.getEndColumn()) return false;
270        return true;
271    }
272
273    public void addOrphanComment(Comment comment) {
274        orphanComments.add(comment);
275        comment.setParentNode(this);
276    }
277
278    /**
279     * This is a list of Comment which are inside the node and are not associated
280     * with any meaningful AST Node.
281     *
282     * For example, comments at the end of methods (immediately before the parenthesis)
283     * or at the end of CompilationUnit are orphan comments.
284     *
285     * When more than one comments preceed a statement, the one immediately preceeding it
286     * it is associated with the statements, while the others are "orphan".
287     * @return all comments that cannot be attributed to a concept
288     */
289    public List<Comment> getOrphanComments() {
290        return orphanComments;
291    }
292
293    /**
294     * This is the list of Comment which are contained in the Node either because
295     * they are properly associated to one of its children or because they are floating
296     * around inside the Node
297     * @return all Comments within the node as a list
298     */
299    public List<Comment> getAllContainedComments() {
300        List<Comment> comments = new LinkedList<Comment>();
301        comments.addAll(getOrphanComments());
302
303        for (Node child : getChildrenNodes()) {
304            if (child.getComment() != null) {
305                comments.add(child.getComment());
306            }
307            comments.addAll(child.getAllContainedComments());
308        }
309
310        return comments;
311    }
312
313    /**
314     * Assign a new parent to this node, removing it
315     * from the list of children of the previous parent, if any.
316     *
317     * @param parentNode node to be set as parent
318     */
319    public void setParentNode(Node parentNode) {
320        // remove from old parent, if any
321        if (this.parentNode != null) {
322            this.parentNode.childrenNodes.remove(this);
323        }
324        this.parentNode = parentNode;
325        // add to new parent, if any
326        if (this.parentNode != null) {
327            this.parentNode.childrenNodes.add(this);
328        }
329    }
330
331    protected void setAsParentNodeOf(List<? extends Node> childNodes) {
332        if (childNodes != null) {
333            Iterator<? extends Node> it = childNodes.iterator();
334            while (it.hasNext()) {
335                Node current = it.next();
336                current.setParentNode(this);
337            }
338        }
339    }
340
341    protected void setAsParentNodeOf(Node childNode) {
342        if (childNode != null) {
343            childNode.setParentNode(this);
344        }
345    }
346
347    public static final int ABSOLUTE_BEGIN_LINE = -1;
348    public static final int ABSOLUTE_END_LINE = -2;
349
350    public boolean isPositionedAfter(int line, int column) {
351        if (line == ABSOLUTE_BEGIN_LINE) return true;
352        if (getBeginLine() > line) {
353            return true;
354        } else if (getBeginLine() == line) {
355            return getBeginColumn() > column;
356        } else {
357            return false;
358        }
359    }
360
361    public boolean isPositionedBefore(int line, int column) {
362        if (line == ABSOLUTE_END_LINE) return true;
363        if (getEndLine() < line) {
364            return true;
365        } else if (getEndLine() == line) {
366            return getEndColumn() < column;
367        } else {
368            return false;
369        }
370    }
371
372    public boolean hasComment()
373    {
374        return comment != null;
375    }
376}
377