001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.debugger.jpda.projects;
043:
044: import com.sun.source.tree.AnnotationTree;
045: import com.sun.source.tree.ArrayAccessTree;
046: import com.sun.source.tree.ArrayTypeTree;
047: import com.sun.source.tree.AssertTree;
048: import com.sun.source.tree.AssignmentTree;
049: import com.sun.source.tree.BinaryTree;
050: import com.sun.source.tree.BlockTree;
051: import com.sun.source.tree.BreakTree;
052: import com.sun.source.tree.CaseTree;
053: import com.sun.source.tree.CatchTree;
054: import com.sun.source.tree.ClassTree;
055: import com.sun.source.tree.CompilationUnitTree;
056: import com.sun.source.tree.CompoundAssignmentTree;
057: import com.sun.source.tree.ConditionalExpressionTree;
058: import com.sun.source.tree.ContinueTree;
059: import com.sun.source.tree.DoWhileLoopTree;
060: import com.sun.source.tree.EmptyStatementTree;
061: import com.sun.source.tree.EnhancedForLoopTree;
062: import com.sun.source.tree.ErroneousTree;
063: import com.sun.source.tree.ExpressionStatementTree;
064: import com.sun.source.tree.ExpressionTree;
065: import com.sun.source.tree.ForLoopTree;
066: import com.sun.source.tree.IdentifierTree;
067: import com.sun.source.tree.IfTree;
068: import com.sun.source.tree.ImportTree;
069: import com.sun.source.tree.InstanceOfTree;
070: import com.sun.source.tree.LabeledStatementTree;
071: import com.sun.source.tree.LineMap;
072: import com.sun.source.tree.LiteralTree;
073: import com.sun.source.tree.MemberSelectTree;
074: import com.sun.source.tree.MethodInvocationTree;
075: import com.sun.source.tree.MethodTree;
076: import com.sun.source.tree.ModifiersTree;
077: import com.sun.source.tree.NewArrayTree;
078: import com.sun.source.tree.NewClassTree;
079: import com.sun.source.tree.ParameterizedTypeTree;
080: import com.sun.source.tree.ParenthesizedTree;
081: import com.sun.source.tree.PrimitiveTypeTree;
082: import com.sun.source.tree.ReturnTree;
083: import com.sun.source.tree.StatementTree;
084: import com.sun.source.tree.SwitchTree;
085: import com.sun.source.tree.SynchronizedTree;
086: import com.sun.source.tree.ThrowTree;
087: import com.sun.source.tree.Tree;
088: import com.sun.source.tree.TreeVisitor;
089: import com.sun.source.tree.TryTree;
090: import com.sun.source.tree.TypeCastTree;
091: import com.sun.source.tree.TypeParameterTree;
092: import com.sun.source.tree.UnaryTree;
093: import com.sun.source.tree.VariableTree;
094: import com.sun.source.tree.WhileLoopTree;
095: import com.sun.source.tree.WildcardTree;
096: import com.sun.source.util.SourcePositions;
097: import com.sun.source.util.TreeScanner;
098:
099: import java.util.ArrayList;
100: import java.util.Collections;
101: import java.util.Comparator;
102: import java.util.HashMap;
103: import java.util.HashSet;
104: import java.util.List;
105: import java.util.Map;
106: import java.util.Set;
107: import java.util.Stack;
108: import java.util.TreeSet;
109:
110: /**
111: * A tree scanner, which collects expressions on a given line.
112: *
113: * @author Martin Entlicher
114: */
115: class ExpressionScanner extends
116: TreeScanner<List<Tree>, ExpressionScanner.ExpressionsInfo> {
117:
118: private int lineNumber;
119: private CompilationUnitTree tree;
120: private SourcePositions positions;
121: private LineMap lineMap;
122: private boolean checkBounds = true;
123:
124: public ExpressionScanner(int lineNumber, CompilationUnitTree tree,
125: SourcePositions positions) {
126: this .tree = tree;
127: this .lineNumber = lineNumber;
128: this .positions = positions;
129: this .lineMap = tree.getLineMap();
130: }
131:
132: private boolean acceptsTree(Tree aTree) {
133: /*
134: int start = (int) positions.getStartPosition(tree, aTree);
135: int end = (int) positions.getEndPosition(tree, aTree);
136: return start <= offset && offset < end;
137: */
138: if (!checkBounds)
139: return true;
140: int startLine = (int) lineMap.getLineNumber(positions
141: .getStartPosition(tree, aTree));
142: if (startLine == lineNumber) {
143: return true;
144: } else {
145: return false;
146: /*
147: return startLine < lineNumber &&
148: lineMap.getLineNumber(positions.getEndPosition(tree, aTree)) >= lineNumber;
149: */
150: }
151: }
152:
153: private boolean isCurrentTree(Tree aTree) {
154: int startLine = (int) lineMap.getLineNumber(positions
155: .getStartPosition(tree, aTree));
156: int endLine = (int) lineMap.getLineNumber(positions
157: .getEndPosition(tree, aTree));
158: return startLine <= lineNumber && lineNumber <= endLine;
159: }
160:
161: public List<Tree> reduce(List<Tree> r1, List<Tree> r2) {
162: if (r1 == null || r1.size() == 0) {
163: return r2;
164: }
165: if (r2 == null || r2.size() == 0) {
166: return r1;
167: }
168: r1.addAll(r2);
169: return r1;
170: }
171:
172: public List<Tree> scan(Iterable<? extends Tree> nodes,
173: ExpressionScanner.ExpressionsInfo p) {
174: List<Tree> r = null;
175: if (nodes != null) {
176: boolean first = true;
177: for (Tree node : nodes) {
178: r = (first ? scan(node, p) : reduce(r, scan(node, p)));
179: first = false;
180: }
181: }
182: return r;
183: }
184:
185: private List<Tree> scan(Tree t1, Tree t2,
186: ExpressionScanner.ExpressionsInfo p) {
187: List<Tree> result = scan(t1, p);
188: result = reduce(result, scan(t2, p));
189: return result;
190: }
191:
192: public List<Tree> visitAnnotation(AnnotationTree node,
193: ExpressionScanner.ExpressionsInfo p) {
194: return null;
195: }
196:
197: public List<Tree> visitMethodInvocation(MethodInvocationTree node,
198: ExpressionScanner.ExpressionsInfo p) {
199: List<Tree> result = scan(node.getTypeArguments(), p);
200: result = reduce(result, scan(node.getMethodSelect(), p));
201: result = reduce(result, scan(node.getArguments(), p));
202: if (result == null) {
203: result = new ArrayList();
204: }
205: result.add(node);
206: return result;
207: }
208:
209: public List<Tree> visitAssert(AssertTree node,
210: ExpressionScanner.ExpressionsInfo p) {
211: List<Tree> result = scan(node.getCondition(), p);
212: result = reduce(result, scan(node.getDetail(), p));
213: return result;
214: }
215:
216: public List<Tree> visitAssignment(AssignmentTree node,
217: ExpressionScanner.ExpressionsInfo p) {
218: return scan(node.getVariable(), node.getExpression(), p);
219: }
220:
221: public List<Tree> visitCompoundAssignment(
222: CompoundAssignmentTree node,
223: ExpressionScanner.ExpressionsInfo p) {
224: return scan(node.getVariable(), node.getExpression(), p);
225: }
226:
227: public List<Tree> visitBinary(BinaryTree node,
228: ExpressionScanner.ExpressionsInfo p) {
229: return scan(node.getLeftOperand(), node.getRightOperand(), p);
230: }
231:
232: //public List<Tree> visitBlock(BlockTree node, ExpressionScanner.ExpressionsInfo p) {
233: //}
234:
235: //public List<Tree> visitBreak(BreakTree node, ExpressionScanner.ExpressionsInfo p) {
236: //}
237:
238: public List<Tree> visitCase(CaseTree node,
239: ExpressionScanner.ExpressionsInfo p) {
240: List<Tree> result = scan(node.getExpression(), p);
241: result = reduce(result, scan(node.getStatements(), p));
242: return result;
243: }
244:
245: //public List<Tree> visitCatch(CatchTree node, ExpressionScanner.ExpressionsInfo p) {
246: //}
247:
248: //public List<Tree> visitClass(ClassTree node, ExpressionScanner.ExpressionsInfo p) {
249: //}
250:
251: public List<Tree> visitConditionalExpression(
252: ConditionalExpressionTree node,
253: ExpressionScanner.ExpressionsInfo p) {
254: List<Tree> cond = scan(node.getCondition(), p);
255: Tree lastCond = null;
256: if (cond != null) {
257: lastCond = cond.get(cond.size() - 1);
258: }
259: List<Tree> rT = scan(node.getTrueExpression(), p);
260: List<Tree> rF = scan(node.getFalseExpression(), p);
261: if (lastCond != null) {
262: if (rT != null) {
263: p.addNextExpression(lastCond, rT.get(0));
264: }
265: if (rF != null) {
266: p.addNextExpression(lastCond, rF.get(0));
267: }
268: }
269: return reduce(reduce(cond, rT), rF);
270: }
271:
272: //public List<Tree> visitContinue(ContinueTree node, ExpressionScanner.ExpressionsInfo p) {
273: //}
274:
275: public List<Tree> visitDoWhileLoop(DoWhileLoopTree node,
276: ExpressionScanner.ExpressionsInfo p) {
277: List<Tree> statements = scan(node.getStatement(), p);
278: List<Tree> cond = null;
279: if (acceptsTree(node.getCondition())) {
280: cond = scan(node.getCondition(), p);
281: }
282: if (cond != null && cond.size() > 0 && statements != null
283: && statements.size() > 0) {
284: Tree lastCond = cond.get(cond.size() - 1);
285: p.addNextExpression(lastCond, statements.get(0));
286: }
287: return reduce(statements, cond);
288: }
289:
290: //public List<Tree> visitErroneous(ErroneousTree node, ExpressionScanner.ExpressionsInfo p) {
291: //}
292:
293: public List<Tree> visitExpressionStatement(
294: ExpressionStatementTree node,
295: ExpressionScanner.ExpressionsInfo p) {
296: if (acceptsTree(node)) {
297: return scan(node.getExpression(), p);
298: } else {
299: return null;
300: }
301: }
302:
303: public List<Tree> visitEnhancedForLoop(EnhancedForLoopTree node,
304: ExpressionScanner.ExpressionsInfo p) {
305: List<Tree> expr = null;
306: if (acceptsTree(node.getExpression())) {
307: expr = scan(node.getExpression(), p);
308: }
309: List<Tree> bodyr = scan(node.getStatement(), p);
310: if (expr != null && expr.size() > 0 && bodyr != null
311: && bodyr.size() > 0) {
312: p
313: .addNextExpression(expr.get(expr.size() - 1), bodyr
314: .get(0));
315: p.addNextExpression(bodyr.get(bodyr.size() - 1), expr
316: .get(0));
317: }
318: return reduce(expr, bodyr);
319: }
320:
321: public List<Tree> visitForLoop(ForLoopTree node,
322: ExpressionScanner.ExpressionsInfo p) {
323: if (!isCurrentTree(node)) {
324: return null;
325: }
326: List<Tree> initr = scan(node.getInitializer(), p);
327: checkBounds = false; // Scan all parts to be able to set the next operations
328: List<Tree> condra = scan(node.getCondition(), p);
329: List<Tree> updtra = scan(node.getUpdate(), p);
330: //List<Tree> bodyra = scan(node.getStatement(), p);
331: checkBounds = true;
332:
333: // And then scan the current (accepted) trees
334: List<Tree> condr = null;
335: if (acceptsTree(node.getCondition())) {
336: condr = scan(node.getCondition(), p);
337: }
338: List<Tree> updtr = scan(node.getUpdate(), p);
339: List<Tree> bodyr = scan(node.getStatement(), p);
340:
341: if (initr != null) {
342: if (condra != null) {
343: p.addNextExpression(initr.get(initr.size() - 1), condra
344: .get(0));
345: } else if (bodyr != null) {
346: p.addNextExpression(initr.get(initr.size() - 1), bodyr
347: .get(0));
348: } else if (updtra != null) {
349: p.addNextExpression(initr.get(initr.size() - 1), updtra
350: .get(0));
351: }
352: }
353: if (condr != null) {
354: if (bodyr != null) {
355: p.addNextExpression(condr.get(condr.size() - 1), bodyr
356: .get(0));
357: } else if (updtra != null) {
358: p.addNextExpression(condr.get(condr.size() - 1), updtra
359: .get(0));
360: }
361: }
362: if (bodyr != null) {
363: if (updtra != null) {
364: p.addNextExpression(bodyr.get(bodyr.size() - 1), updtra
365: .get(0));
366: } else if (condra != null) {
367: p.addNextExpression(bodyr.get(bodyr.size() - 1), condra
368: .get(0));
369: }
370: }
371: if (updtr != null) {
372: if (condra != null) {
373: p.addNextExpression(updtr.get(updtr.size() - 1), condra
374: .get(0));
375: } else if (bodyr != null) {
376: p.addNextExpression(updtr.get(updtr.size() - 1), bodyr
377: .get(0));
378: }
379: }
380: return reduce(reduce(reduce(initr, condr), bodyr), updtr);
381: }
382:
383: //public List<Tree> visitIdentifier(IdentifierTree node, ExpressionScanner.ExpressionsInfo p) {
384: //}
385:
386: public List<Tree> visitIf(IfTree node,
387: ExpressionScanner.ExpressionsInfo p) {
388: List<Tree> cond = null;
389: Tree lastCond = null;
390: if (acceptsTree(node)) {
391: cond = scan(node.getCondition(), p);
392: if (cond != null) {
393: lastCond = cond.get(cond.size() - 1);
394: }
395: }
396: StatementTree thent = node.getThenStatement();
397: StatementTree elset = node.getElseStatement();
398: List<Tree> thenr = null;
399: if (isCurrentTree(thent)) {
400: thenr = scan(thent, p);
401: if (lastCond != null && thenr != null) {
402: p.addNextExpression(lastCond, thenr.get(0));
403: }
404: }
405: List<Tree> elser = null;
406: if (isCurrentTree(elset)) {
407: elser = scan(elset, p);
408: if (lastCond != null && elser != null) {
409: p.addNextExpression(lastCond, elser.get(0));
410: }
411: }
412: return reduce(reduce(cond, thenr), elser);
413: }
414:
415: //public List<Tree> visitImport(ImportTree node, ExpressionScanner.ExpressionsInfo p) {
416: //}
417:
418: public List<Tree> visitArrayAccess(ArrayAccessTree node,
419: ExpressionScanner.ExpressionsInfo p) {
420: return scan(node.getExpression(), node.getIndex(), p);
421: }
422:
423: //public List<Tree> visitLabeledStatement(LabeledStatementTree node, ExpressionScanner.ExpressionsInfo p) {
424: //}
425:
426: //public List<Tree> visitLiteral(LiteralTree node, ExpressionScanner.ExpressionsInfo p) {
427: //}
428:
429: //public List<Tree> visitMethod(MethodTree node, ExpressionScanner.ExpressionsInfo p) {
430: //}
431:
432: public List<Tree> visitModifiers(ModifiersTree node,
433: ExpressionScanner.ExpressionsInfo p) {
434: return null;
435: }
436:
437: public List<Tree> visitNewArray(NewArrayTree node,
438: ExpressionScanner.ExpressionsInfo p) {
439: List<Tree> result = scan(node.getType(), p);
440: result = reduce(result, scan(node.getDimensions(), p));
441: result = reduce(result, scan(node.getInitializers(), p));
442: return result;
443: }
444:
445: public List<Tree> visitNewClass(NewClassTree node,
446: ExpressionScanner.ExpressionsInfo p) {
447: List<Tree> result = scan(node.getEnclosingExpression(), node
448: .getIdentifier(), p);
449: result = reduce(result, scan(node.getArguments(), p));
450: result = reduce(result, scan(node.getClassBody(), p));
451: if (result == null) {
452: result = new ArrayList();
453: }
454: result.add(node);
455: return result;
456: }
457:
458: //public List<Tree> visitParenthesized(ParenthesizedTree node, ExpressionScanner.ExpressionsInfo p) {
459: //}
460:
461: //public List<Tree> visitReturn(ReturnTree node, ExpressionScanner.ExpressionsInfo p) {
462: //}
463:
464: //public List<Tree> visitMemberSelect(MemberSelectTree node, ExpressionScanner.ExpressionsInfo p) {
465: //}
466:
467: //public List<Tree> visitEmptyStatement(EmptyStatementTree node, ExpressionScanner.ExpressionsInfo p) {
468: //}
469:
470: public List<Tree> visitSwitch(SwitchTree node,
471: ExpressionScanner.ExpressionsInfo p) {
472: List<Tree> result = null;
473: if (acceptsTree(node)) {
474: result = scan(node.getExpression(), p);
475: }
476: return reduce(result, scan(node.getCases(), p));
477: }
478:
479: public List<Tree> visitSynchronized(SynchronizedTree node,
480: ExpressionScanner.ExpressionsInfo p) {
481: List<Tree> result = null;
482: if (acceptsTree(node)) {
483: result = scan(node.getExpression(), p);
484: }
485: return reduce(result, scan(node.getBlock(), p));
486: }
487:
488: //public List<Tree> visitThrow(ThrowTree node, ExpressionScanner.ExpressionsInfo p) {
489: //}
490:
491: //public List<Tree> visitCompilationUnit(CompilationUnitTree node, ExpressionScanner.ExpressionsInfo p) {
492: //}
493:
494: //public List<Tree> visitTry(TryTree node, ExpressionScanner.ExpressionsInfo p) {
495: //}
496:
497: public List<Tree> visitParameterizedType(
498: ParameterizedTypeTree node,
499: ExpressionScanner.ExpressionsInfo p) {
500: return null;
501: }
502:
503: //public List<Tree> visitArrayType(ArrayTypeTree node, ExpressionScanner.ExpressionsInfo p) {
504: //}
505:
506: public List<Tree> visitTypeCast(TypeCastTree node,
507: ExpressionScanner.ExpressionsInfo p) {
508: return scan(node.getExpression(), p);
509: }
510:
511: //public List<Tree> visitPrimitiveType(PrimitiveTypeTree node, ExpressionScanner.ExpressionsInfo p) {
512: //}
513:
514: //public List<Tree> visitTypeParameter(TypeParameterTree node, ExpressionScanner.ExpressionsInfo p) {
515: //}
516:
517: public List<Tree> visitInstanceOf(InstanceOfTree node,
518: ExpressionScanner.ExpressionsInfo p) {
519: return scan(node.getExpression(), node.getType(), p);
520: }
521:
522: public List<Tree> visitUnary(UnaryTree node,
523: ExpressionScanner.ExpressionsInfo p) {
524: return scan(node.getExpression(), p);
525: }
526:
527: public List<Tree> visitVariable(VariableTree node,
528: ExpressionScanner.ExpressionsInfo p) {
529: if (acceptsTree(node)) {
530: return scan(node.getInitializer(), p);
531: } else {
532: return null;
533: }
534: }
535:
536: public List<Tree> visitWhileLoop(WhileLoopTree node,
537: ExpressionScanner.ExpressionsInfo p) {
538: List<Tree> cond = null;
539: if (acceptsTree(node.getCondition())) {
540: cond = scan(node.getCondition(), p);
541: }
542: List<Tree> statements = scan(node.getStatement(), p);
543: if (cond != null && statements != null && statements.size() > 0) {
544: p.addNextExpression(statements.get(statements.size() - 1),
545: cond.get(0));
546: }
547: return reduce(cond, statements);
548: }
549:
550: //public List<Tree> visitWildcard(WildcardTree node, ExpressionScanner.ExpressionsInfo p) {
551: //}
552:
553: public List<Tree> visitOther(Tree node,
554: ExpressionScanner.ExpressionsInfo p) {
555: return null;
556: }
557:
558: /** Provides further information about the expressions. */
559: public static final class ExpressionsInfo extends Object {
560:
561: private Map<Tree, Set<Tree>> nextExpressions = new HashMap<Tree, Set<Tree>>();
562: Stack<StatementTree> wrappingStatements = new Stack<StatementTree>();
563:
564: synchronized void addNextExpression(Tree expression, Tree next) {
565: Set<Tree> nexts = nextExpressions.get(expression);
566: if (nexts == null) {
567: nexts = new HashSet<Tree>();
568: nextExpressions.put(expression, nexts);
569: }
570: nexts.add(next);
571: }
572:
573: synchronized Set<Tree> getNextExpressions(Tree expression) {
574: Set<Tree> nexts = nextExpressions.get(expression);
575: if (nexts == null) {
576: return Collections.emptySet();
577: } else {
578: return nexts;
579: }
580: }
581: }
582: }
|