001: package javaparser;
002:
003: import javaparser.javacc_gen.Token;
004: import java.io.*;
005: import java.util.*;
006: import javax.swing.text.*;
007: import javax.swing.tree.*;
008:
009: public final class TreeUtils {
010: private TreeUtils() {
011: }
012:
013: /** Be careful, the spaces are not tokens, therefore no space will be matched by any token.
014: it is better to use the parsed simplified Nodes to scan in which block some input is rather than to
015: search for an exact token match.
016: @param line starts with 1
017: */
018: public static boolean contains(Token t, int line, int col) {
019: if (t == null)
020: return false;
021: if (line < t.beginLine)
022: return false;
023: if (line > t.endLine)
024: return false;
025: if (line == t.beginLine && col < t.beginColumn)
026: return false;
027: if (line == t.endLine && col > t.endColumn)
028: return false;
029:
030: return true; // ok !
031: }
032:
033: /** can be boosted a little bit...
034: */
035: public static boolean isTokenContainingOrAfter(Token t, int line,
036: int col) {
037: if (contains(t, line, col))
038: return true;
039:
040: // true if token is AFTER !
041: if (line < t.beginLine)
042: return true;
043: if (line == t.beginLine && col < t.beginColumn)
044: return true;
045:
046: return false; // ok !
047: }
048:
049: /** allow in or just after (1 line)
050: */
051: public static boolean isPositionInOrJustAfter(Token t, int line,
052: int col) {
053: if (t == null)
054: return false;
055:
056: if (contains(t, line, col))
057: return true;
058:
059: // so we know that it doesn't contain the pos, we just return if the pos is after
060:
061: if (t.endLine <= line && t.endLine + 1 >= line)
062: return true;
063:
064: return false;
065: }
066:
067: /** @param line starts with 1
068: */
069: public static boolean contains(ParserTreeNode t, int line, int col) {
070: if (t == null)
071: return false;
072: if (line < t.getStartLinCol()[0])
073: return false;
074: if (line > t.getEndLinCol()[0])
075: return false;
076: if (line == t.getStartLinCol()[0]
077: && col < t.getStartLinCol()[1])
078: return false;
079: if (line == t.getEndLinCol()[0] && col > t.getEndLinCol()[1])
080: return false;
081:
082: return true; // ok !
083: }
084:
085: /** search for a token containing exactely the position. (DEPTH FIRST => ???)
086: often don't exist ! use only for debug and completion type discover (IDResolver) in the RAW syntax tree (=tn)
087: BETTER: use getFirstNodeBeforePosition to allow some tolerance when completing with old raw trees
088: */
089: public static RAWParserTreeNode getNodeTokenContaining(
090: RAWParserTreeNode tn, int line, int col) {
091: if (tn.isToken() && contains(tn.getToken(), line, col))
092: return tn;
093:
094: for (int i = 0; i < tn.getChildCount(); i++) {
095: RAWParserTreeNode found = getNodeTokenContaining(tn
096: .getChildNodeAt(i), line, col);
097: if (found != null)
098: return found;
099: }
100:
101: //not found
102: return null;
103: }
104:
105: /** The node containing or just before
106: getNodeTokenContaining often don't exist,
107: this did sometimes more often exist :-) !!
108: especially when editing (inserting text chars) and using an old tree
109: NOT WORKING WELL, TOO IMPRECISE ! use getTokenNodeAtOrAfterPosition instead !!!
110: */
111: public static ParserTreeNode getFirstTokenNodeBeforePosition(
112: ParserTreeNode tn, int line, int col) {
113: if (tn.isToken()
114: && isPositionInOrJustAfter(tn.getToken(), line, col))
115: return tn;
116:
117: for (int i = 0; i < tn.getChildCount(); i++) {
118: ParserTreeNode found = getFirstTokenNodeBeforePosition(tn
119: .getChildNodeAt(i), line, col);
120: if (found != null)
121: return found;
122: }
123:
124: //not found
125: return null;
126: }
127:
128: /** The node containing or just after the given position.
129: * Robust when the RAW tokens tree is walked down (depth first), this returns the first element direct after the position.
130: */
131: @tide.annotations.Recurse
132: public static RAWParserTreeNode getTokenNodeAtOrAfterPosition(
133: RAWParserTreeNode tn, int line, int col) {
134: if (tn.t != null && isTokenContainingOrAfter(tn.t, line, col))
135: return tn;
136:
137: for (int i = 0; i < tn.getChildCount(); i++) {
138: RAWParserTreeNode found = getTokenNodeAtOrAfterPosition(tn
139: .getChildNodeAt(i), line, col);
140: if (found != null)
141: return found;
142: }
143:
144: //not found
145: return null;
146: }
147:
148: /** Walk up in the RAW tree and return the next declarator (LocalVariableDeclaration or FormalParameter node)
149: * maybe raw, in a for loop, in a method, ...
150: * Previous means that the tree is only looked at previous siblings (and then down) and node up !
151: * actually, this only looks backward for types declared before the position of "from". that means that this is only suitable for variables,
152: * not for fields or methds that have a bigger scope (class).
153: * @param methodCallsOnly true if you know that you're searching for a method call like "hello(12)", use name="hello", methodCallsOnly=true
154: */
155: public static String searchTypeForVariableName(
156: RAWParserTreeNode fromInRAW, String name,
157: boolean methodCallsOnly) {
158: List<RAWParserTreeNode> nodePreviousSiblings = null;
159: RAWParserTreeNode actualNode = fromInRAW;
160:
161: if (!methodCallsOnly) {
162: // recurse the tree back
163: sr: while (actualNode != null) {
164: // first look in the parent node itself
165: String type = lookInBranchForTypeForParameter(
166: actualNode, name);
167: if (type != null)
168: return type;
169:
170: // look at siblings (recurse !)
171: nodePreviousSiblings = getPreviousSiblings(actualNode);
172: if (nodePreviousSiblings == null)
173: break sr; // root
174: //System.out.println("Siblings: "+nodePreviousSiblings);
175:
176: for (RAWParserTreeNode sn : nodePreviousSiblings) {
177: // looks down !
178: type = lookInBranchForTypeForParameter(sn, name);
179: if (type != null)
180: return type;
181: }
182:
183: // go one step higher in the tree
184: actualNode = actualNode.parent;
185: if (actualNode.parent == null)
186: break sr; //ROOT
187: }
188: }
189:
190: // not found in the variables => caller must look in the methods and fields of the class
191: return null;
192: }
193:
194: /** Walk up in the RAW tree and return the next declarator (LocalVariableDeclaration or FormalParameter node)
195: * maybe raw, in a for loop, in a method, ...
196: * Previous means that the tree is only looked at previous siblings (and then down) and node up !
197: * actually, this only looks backward for types declared before the position of "from". that means that this is only suitable for variables,
198: * not for fields or methds that have a bigger scope (class).
199: *
200: * STOPS AT FIRST METHOD DECL !
201: * all variables dclared after fromInRAW are ignored !
202: */
203: public static void collectLocalVariablesBefore(
204: RAWParserTreeNode fromInRAW, int beforeLine,
205: java.util.List<Parameter> params) {
206: List<RAWParserTreeNode> nodePreviousSiblings = null;
207: RAWParserTreeNode actualNode = fromInRAW;
208:
209: // recurse the tree back
210: sr: while (actualNode != null) {
211: //System.out.println("Look in branch "+actualNode);
212: // first look in the parent node itself
213: lookInBranchForParameters(actualNode, beforeLine, params);
214:
215: // look at siblings (recurse !)
216: nodePreviousSiblings = getPreviousSiblings(actualNode);
217: if (nodePreviousSiblings == null)
218: break sr; // root
219:
220: //System.out.println("Siblings: "+nodePreviousSiblings);
221:
222: for (RAWParserTreeNode sn : nodePreviousSiblings) {
223: // looks down !
224: lookInBranchForParameters(sn, beforeLine, params);
225: }
226:
227: // go one step higher in the tree
228: actualNode = actualNode.parent;
229: if (actualNode.parent == null)
230: break sr; // ROOT
231:
232: if (actualNode.toString().equals("MethodDeclaration")) {
233: // TODO: maybe let jump higher in tree, because of anonymous classes !
234: break sr;
235: }
236:
237: }
238:
239: // not found in the variables => caller must look in the methods and fields of the class
240: }
241:
242: /** recursive look for parameters. Used for completion of local variables (F2)
243: * slow, collect all but methods and fields (only preceedings)
244: * TODO: limit to scopes !
245: */
246: public static void lookInBranchForParameters(
247: RAWParserTreeNode from, int beforeLine,
248: java.util.List<Parameter> params) {
249: for (int i = 0; i < from.getChildCount(); i++) {
250: RAWParserTreeNode ptn = from.getChildNodeAt(i);
251: if (ptn.toString().equals("FormalParameter")) {
252: Parameter parameter = Parameter
253: .parseFromFormalParamNode(ptn);
254: //System.out.println("** Param: "+parameter);
255: if (parameter != null
256: && !parameter.isParameterAfterLine(beforeLine))
257: params.add(parameter);
258: } else if (ptn.toString()
259: .equals("LocalVariableDeclaration")) {
260: Parameter parameter = Parameter
261: .parseFromLocalVariableDeclaration(ptn);
262: //System.out.println("** Param loc var : "+parameter);
263: if (parameter != null
264: && !parameter.isParameterAfterLine(beforeLine))
265: params.add(parameter);
266: }
267: /*else if(ptn.toString().equals("FieldDeclaration")) // not necessary...
268: {
269: Parameter parameter = Parameter.parseFromFieldDeclaration(ptn);
270: //System.out.println("** Param field : "+parameter);
271: if(parameter!=null) params.add(parameter);
272: }*/
273: else if (ptn.toString().equals("ForStatement")) {
274: Parameter parameter = Parameter
275: .parseFromForStatementDeclaration(ptn);
276: //System.out.println("** Param for for loop : "+parameter);
277: // param may be null because some for statement doesn't initialize variables
278: if (parameter != null
279: && !parameter.isParameterAfterLine(beforeLine))
280: params.add(parameter);
281: }
282: /*else if(ptn.toString().equals("MethodDeclaration")) // not necessary...
283: {
284: Parameter parameter = Parameter.parseFromMethodDeclaration(ptn);
285: if(parameter!=null && !parameter.isParameterAfterLine(beforeLine)) params.add(parameter);
286: }*/
287: else {
288: // recurse (TODO: limit to some nodes, look in the raw tree for "ideas" )
289: lookInBranchForParameters(ptn, beforeLine, params);
290: }
291: }
292: }
293:
294: /** this look into the RAW tree (down) for parameters with the given name.
295: * quick because stops at first occurence.
296: * (TODO: some nodes have no chance to contain parameters => abort!)
297: * this is also not efficient for method and fields (look in the simplified tree instead !)
298: */
299: public static String lookInBranchForTypeForParameter(
300: RAWParserTreeNode from, String name) {
301: //System.out.println("Look in "+from+" for "+name);
302: for (int i = 0; i < from.getChildCount(); i++) {
303: RAWParserTreeNode ptn = from.getChildNodeAt(i);
304: if (ptn.toString().equals("FormalParameter")) {
305: Parameter parameter = Parameter
306: .parseFromFormalParamNode(ptn);
307: //System.out.println("** Param: "+parameter);
308: if (parameter.name.equals(name))
309: return parameter.type;
310: } else if (ptn.toString()
311: .equals("LocalVariableDeclaration")) {
312: Parameter parameter = Parameter
313: .parseFromLocalVariableDeclaration(ptn);
314: //System.out.println("** Param loc var : "+parameter);
315: if (parameter.name.equals(name))
316: return parameter.type;
317: } else if (ptn.toString().equals("FieldDeclaration")) // not necessary...
318: {
319: Parameter parameter = Parameter
320: .parseFromFieldDeclaration(ptn);
321: //System.out.println("** Param field : "+parameter);
322: if (parameter.name.equals(name))
323: return parameter.type;
324: } else if (ptn.toString().equals("ForStatement")) {
325: Parameter parameter = Parameter
326: .parseFromForStatementDeclaration(ptn);
327: //System.out.println("** Param for for loop : "+parameter);
328: // param may be null because some for statement doesn't initialize variables
329: if (parameter != null && parameter.name.equals(name))
330: return parameter.type;
331: } else if (ptn.toString().equals("MethodDeclaration")) // not necessary...
332: {
333: Parameter parameter = Parameter
334: .parseFromMethodDeclaration(ptn);
335: if (parameter != null) {
336: //System.out.println("** Param for method : "+parameter);
337: if (parameter.name.equals(name))
338: return parameter.type;
339: } else {
340: System.out.println("No param for method !!");
341: }
342: } else {
343: // recurse (TODO: limit to some nodes, look in the raw tree for "ideas" )
344: String found = lookInBranchForTypeForParameter(ptn,
345: name);
346: if (found != null)
347: return found;
348: }
349: }
350: // not found
351: return null;
352: }
353:
354: /** @return null if no parent found for from
355: * (order = first element is the just preceding)
356: */
357: @edu.umd.cs.findbugs.annotations.CheckForNull
358: private static List<RAWParserTreeNode> getPreviousSiblings(
359: RAWParserTreeNode from) {
360: List<RAWParserTreeNode> ps = new ArrayList<RAWParserTreeNode>();
361: RAWParserTreeNode parent = from.parent;
362: if (parent == null)
363: return null;
364:
365: int pos = parent.getIndex(from);
366: for (int i = pos - 1; i >= 0; i--) // pos-1 because we really want from the previous, NOT !
367: {
368: ps.add(parent.getChildNodeAt(i));
369: }
370:
371: return ps;
372: }
373:
374: /** search for a token containing exactely the position.
375: often don't exist ! use only for debug
376: */
377: @edu.umd.cs.findbugs.annotations.CheckForNull
378: public static ParserTreeNode getBlokContaining(ParserTreeNode tn,
379: int line, int col) {
380: if (tn.isToken() && contains(tn.getToken(), line, col))
381: return tn;
382:
383: for (int i = 0; i < tn.getChildCount(); i++) {
384: ParserTreeNode found = getBlokContaining(tn
385: .getChildNodeAt(i), line, col);
386: if (found != null)
387: return found;
388: }
389:
390: //not found
391: return null;
392: }
393:
394: /** @param classOrInterface may also be an enum or an annotation.
395: */
396: public static List<ParserTreeNode> getAllMethodsAndFieldsForType(
397: ParserTreeNode classOrInterface) {
398: // collect all childs
399: //
400: List<ParserTreeNode> allMethodsAndFields = new ArrayList<ParserTreeNode>();
401: for (int i = 0; i < classOrInterface.getChildCount(); i++) {
402: ParserTreeNode ni = classOrInterface.getChildNodeAt(i);
403:
404: /*old
405:
406: if(ni instanceof MainModifierNode) // public, private, prot, packsc
407: {
408: for(int j=0; j<ni.getChildCount(); j++)
409: {
410: allMethodsAndFields.add( ni.getChildNodeAt(j) );
411: }
412: }
413: */
414:
415: // new:
416: allMethodsAndFields.add(ni);
417:
418: }
419: return allMethodsAndFields;
420: }
421:
422: /** This do NOT look in the raw tree. Returns the first containing.
423: Depth first recursive search
424: */
425: public static ParserTreeNode getNearestSimplifiedNode(
426: ParserTreeNode node, int line, int col) {
427: if (node.isRawTreeRoot)
428: return null;
429:
430: // depth first
431: for (int i = 0; i < node.getChildCount(); i++) {
432: ParserTreeNode ci = node.getChildNodeAt(i);
433:
434: ParserTreeNode found = getNearestSimplifiedNode(ci, line,
435: col);
436:
437: if (found != null)
438: return found;
439: }
440:
441: if (contains(node, line, col))
442: return node;
443: return null;
444: }
445:
446: public static ParserTreeNode getChildWithStringRep(
447: ParserTreeNode tn, String str) {
448: for (int i = 0; i < tn.getChildCount(); i++) {
449: ParserTreeNode tni = tn.getChildNodeAt(i);
450: if (tni.toString().equals(str))
451: return tni;
452: }
453: //not found
454: return null;
455: }
456:
457: }
|