Source Code Cross Referenced for AstUtilities.java in  » IDE-Netbeans » ruby » org » netbeans » modules » ruby » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » ruby » org.netbeans.modules.ruby 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:        package org.netbeans.modules.ruby;
0042:
0043:        import java.io.IOException;
0044:        import java.util.ArrayList;
0045:        import java.util.Collections;
0046:        import java.util.HashMap;
0047:        import java.util.HashSet;
0048:        import java.util.Iterator;
0049:        import java.util.LinkedList;
0050:        import java.util.List;
0051:        import java.util.Map;
0052:        import java.util.Set;
0053:
0054:        import javax.swing.text.BadLocationException;
0055:        import javax.swing.text.Document;
0056:
0057:        import org.jruby.ast.AliasNode;
0058:        import org.jruby.ast.ArgsCatNode;
0059:        import org.jruby.ast.ArgsNode;
0060:        import org.jruby.ast.ArgumentNode;
0061:        import org.jruby.ast.AssignableNode;
0062:        import org.jruby.ast.CallNode;
0063:        import org.jruby.ast.ClassNode;
0064:        import org.jruby.ast.Colon2Node;
0065:        import org.jruby.ast.Colon3Node;
0066:        import org.jruby.ast.ConstNode;
0067:        import org.jruby.ast.FCallNode;
0068:        import org.jruby.ast.IScopingNode;
0069:        import org.jruby.ast.ListNode;
0070:        import org.jruby.ast.LocalAsgnNode;
0071:        import org.jruby.ast.MethodDefNode;
0072:        import org.jruby.ast.ModuleNode;
0073:        import org.jruby.ast.Node;
0074:        import org.jruby.ast.NodeTypes;
0075:        import org.jruby.ast.SClassNode;
0076:        import org.jruby.ast.StrNode;
0077:        import org.jruby.ast.SymbolNode;
0078:        import org.jruby.ast.VCallNode;
0079:        import org.jruby.ast.types.INameNode;
0080:        import org.jruby.lexer.yacc.ISourcePosition;
0081:        import org.jruby.util.ByteList;
0082:        import org.netbeans.modules.gsf.api.CancellableTask;
0083:        import org.netbeans.modules.gsf.api.CompilationInfo;
0084:        import org.netbeans.modules.gsf.api.Modifier;
0085:        import org.netbeans.modules.gsf.api.NameKind;
0086:        import org.netbeans.modules.gsf.api.OffsetRange;
0087:        import org.netbeans.modules.gsf.api.Parser;
0088:        import org.netbeans.modules.gsf.api.ParserFile;
0089:        import org.netbeans.modules.gsf.api.ParserResult;
0090:        import org.netbeans.modules.gsf.api.SourceFileReader;
0091:        import org.netbeans.modules.gsf.api.SourceModel;
0092:        import org.netbeans.modules.gsf.api.SourceModelFactory;
0093:        import org.netbeans.modules.gsf.api.TranslatedSource;
0094:        import org.netbeans.editor.BaseDocument;
0095:        import org.netbeans.editor.Utilities;
0096:        import org.netbeans.modules.ruby.elements.IndexedElement;
0097:        import org.netbeans.modules.ruby.elements.IndexedField;
0098:        import org.netbeans.modules.ruby.elements.IndexedMethod;
0099:        import org.netbeans.modules.ruby.lexer.LexUtilities;
0100:        import org.netbeans.modules.gsf.spi.DefaultParseListener;
0101:        import org.openide.filesystems.FileObject;
0102:        import org.openide.util.Exceptions;
0103:
0104:        /**
0105:         * Various utilities for operating on the JRuby ASTs that are used
0106:         * elsewhere.
0107:         * 
0108:         * @todo Rewrite many of the custom recursion routines to simply 
0109:         *  call {@link addNodesByType} and then iterate (without recursion) over
0110:         *  the result set.
0111:         *
0112:         * @author Tor Norbye
0113:         */
0114:        public class AstUtilities {
0115:            /** Whether or not the prefixes for defs should be highlighted, e.g. in
0116:             *   def HTTP.foo
0117:             * Should "HTTP." be highlighted, or just the foo portion?
0118:             */
0119:            private static final boolean INCLUDE_DEFS_PREFIX = false;
0120:
0121:            public static int getAstOffset(CompilationInfo info, int lexOffset) {
0122:                ParserResult result = info.getEmbeddedResult(
0123:                        RubyMimeResolver.RUBY_MIME_TYPE, 0);
0124:                if (result != null) {
0125:                    TranslatedSource ts = result.getTranslatedSource();
0126:                    if (ts != null) {
0127:                        return ts.getAstOffset(lexOffset);
0128:                    }
0129:                }
0130:
0131:                return lexOffset;
0132:            }
0133:
0134:            public static OffsetRange getAstOffsets(CompilationInfo info,
0135:                    OffsetRange lexicalRange) {
0136:                ParserResult result = info.getEmbeddedResult(
0137:                        RubyMimeResolver.RUBY_MIME_TYPE, 0);
0138:                if (result != null) {
0139:                    TranslatedSource ts = result.getTranslatedSource();
0140:                    if (ts != null) {
0141:                        int rangeStart = lexicalRange.getStart();
0142:                        int start = ts.getAstOffset(rangeStart);
0143:                        if (start == rangeStart) {
0144:                            return lexicalRange;
0145:                        } else if (start == -1) {
0146:                            return OffsetRange.NONE;
0147:                        } else {
0148:                            // Assumes the translated range maintains size
0149:                            return new OffsetRange(start, start
0150:                                    + lexicalRange.getLength());
0151:                        }
0152:                    }
0153:                }
0154:                return lexicalRange;
0155:            }
0156:
0157:            /** This is a utility class only, not instantiatiable */
0158:            private AstUtilities() {
0159:            }
0160:
0161:            /**
0162:             * Get the rdoc documentation associated with the given node in the given document.
0163:             * The node must have position information that matches the source in the document.
0164:             */
0165:            public static List<String> gatherDocumentation(
0166:                    CompilationInfo info, BaseDocument baseDoc, Node node) {
0167:                LinkedList<String> comments = new LinkedList<String>();
0168:                int elementBegin = node.getPosition().getStartOffset();
0169:                if (info != null) {
0170:                    elementBegin = LexUtilities.getLexerOffset(info,
0171:                            elementBegin);
0172:                }
0173:
0174:                try {
0175:                    if (elementBegin >= baseDoc.getLength()) {
0176:                        return null;
0177:                    }
0178:
0179:                    // Search to previous lines, locate comments. Once we have a non-whitespace line that isn't
0180:                    // a comment, we're done
0181:
0182:                    int offset = Utilities.getRowStart(baseDoc, elementBegin);
0183:                    offset--;
0184:
0185:                    // Skip empty and whitespace lines
0186:                    while (offset >= 0) {
0187:                        // Find beginning of line
0188:                        offset = Utilities.getRowStart(baseDoc, offset);
0189:
0190:                        if (!Utilities.isRowEmpty(baseDoc, offset)
0191:                                && !Utilities.isRowWhite(baseDoc, offset)) {
0192:                            break;
0193:                        }
0194:
0195:                        offset--;
0196:                    }
0197:
0198:                    if (offset < 0) {
0199:                        return null;
0200:                    }
0201:
0202:                    while (offset >= 0) {
0203:                        // Find beginning of line
0204:                        offset = Utilities.getRowStart(baseDoc, offset);
0205:
0206:                        if (Utilities.isRowEmpty(baseDoc, offset)
0207:                                || Utilities.isRowWhite(baseDoc, offset)) {
0208:                            // Empty lines not allowed within an rdoc
0209:                            break;
0210:                        }
0211:
0212:                        // This is a comment line we should include
0213:                        int lineBegin = Utilities.getRowFirstNonWhite(baseDoc,
0214:                                offset);
0215:                        int lineEnd = Utilities.getRowLastNonWhite(baseDoc,
0216:                                offset) + 1;
0217:                        String line = baseDoc.getText(lineBegin, lineEnd
0218:                                - lineBegin);
0219:
0220:                        // Tolerate "public", "private" and "protected" here --
0221:                        // Test::Unit::Assertions likes to put these in front of each
0222:                        // method.
0223:                        if (line.startsWith("#")) {
0224:                            comments.addFirst(line);
0225:                        } else if ((comments.size() == 0)
0226:                                && line.startsWith("=end")
0227:                                && (lineBegin == Utilities.getRowStart(baseDoc,
0228:                                        offset))) {
0229:                            // It could be a =begin,=end document - see scanf.rb in Ruby lib for example. Treat this differently.
0230:                            gatherInlineDocumentation(comments, baseDoc, offset);
0231:
0232:                            return comments;
0233:                        } else if (line.equals("public")
0234:                                || line.equals("private")
0235:                                || line.equals("protected")) { // NOI18N
0236:                            // Skip newlines back up to the comment
0237:                            offset--;
0238:
0239:                            while (offset >= 0) {
0240:                                // Find beginning of line
0241:                                offset = Utilities.getRowStart(baseDoc, offset);
0242:
0243:                                if (!Utilities.isRowEmpty(baseDoc, offset)
0244:                                        && !Utilities.isRowWhite(baseDoc,
0245:                                                offset)) {
0246:                                    break;
0247:                                }
0248:
0249:                                offset--;
0250:                            }
0251:
0252:                            continue;
0253:                        } else {
0254:                            // No longer in a comment
0255:                            break;
0256:                        }
0257:
0258:                        // Previous line
0259:                        offset--;
0260:                    }
0261:                } catch (BadLocationException ble) {
0262:                    Exceptions.printStackTrace(ble);
0263:                }
0264:
0265:                return comments;
0266:            }
0267:
0268:            private static void gatherInlineDocumentation(
0269:                    LinkedList<String> comments, BaseDocument baseDoc,
0270:                    int offset) throws BadLocationException {
0271:                // offset points to a line containing =end
0272:                // Skip the =end list
0273:                offset = Utilities.getRowStart(baseDoc, offset);
0274:                offset--;
0275:
0276:                // Search backwards in the document for the =begin (if any) and add all lines in reverse
0277:                // order in between.
0278:                while (offset >= 0) {
0279:                    // Find beginning of line
0280:                    offset = Utilities.getRowStart(baseDoc, offset);
0281:
0282:                    // This is a comment line we should include
0283:                    int lineBegin = offset;
0284:                    int lineEnd = Utilities.getRowEnd(baseDoc, offset);
0285:                    String line = baseDoc.getText(lineBegin, lineEnd
0286:                            - lineBegin);
0287:
0288:                    if (line.startsWith("=begin")) {
0289:                        // We're done!
0290:                        return;
0291:                    }
0292:
0293:                    comments.addFirst(line);
0294:
0295:                    // Previous line
0296:                    offset--;
0297:                }
0298:            }
0299:
0300:            public static Node getForeignNode(final IndexedElement o,
0301:                    Node[] foreignRootRet) {
0302:                ParserFile file = o.getFile();
0303:
0304:                if (file == null) {
0305:                    return null;
0306:                }
0307:
0308:                List<ParserFile> files = Collections.singletonList(file);
0309:                SourceFileReader reader = new SourceFileReader() {
0310:                    public CharSequence read(ParserFile file)
0311:                            throws IOException {
0312:                        Document doc = o.getDocument();
0313:
0314:                        if (doc == null) {
0315:                            return "";
0316:                        }
0317:
0318:                        try {
0319:                            return doc.getText(0, doc.getLength());
0320:                        } catch (BadLocationException ble) {
0321:                            IOException ioe = new IOException();
0322:                            ioe.initCause(ble);
0323:                            throw ioe;
0324:                        }
0325:                    }
0326:
0327:                    public int getCaretOffset(ParserFile fileObject) {
0328:                        return -1;
0329:                    }
0330:                };
0331:
0332:                DefaultParseListener listener = new DefaultParseListener();
0333:                // TODO - embedding model?
0334:                TranslatedSource translatedSource = null; // TODO - determine this here?                
0335:                Parser.Job job = new Parser.Job(files, listener, reader,
0336:                        translatedSource);
0337:                new RubyParser().parseFiles(job);
0338:
0339:                ParserResult result = listener.getParserResult();
0340:
0341:                if (result == null) {
0342:                    return null;
0343:                }
0344:
0345:                Node root = AstUtilities.getRoot(result);
0346:
0347:                if (root == null) {
0348:                    return null;
0349:                } else if (foreignRootRet != null) {
0350:                    foreignRootRet[0] = root;
0351:                }
0352:
0353:                String signature = o.getSignature();
0354:
0355:                if (signature == null) {
0356:                    return null;
0357:                }
0358:
0359:                Node node = AstUtilities.findBySignature(root, signature);
0360:
0361:                // Special handling for "new" - these are synthesized from "initialize" methods
0362:                if ((node == null) && "new".equals(o.getName())) { // NOI18N
0363:                    signature = signature.replaceFirst("new", "initialize"); //NOI18N
0364:                    node = AstUtilities.findBySignature(root, signature);
0365:                }
0366:
0367:                return node;
0368:            }
0369:
0370:            public static int boundCaretOffset(CompilationInfo info,
0371:                    int caretOffset) {
0372:                Document doc = null;
0373:
0374:                try {
0375:                    doc = info.getDocument();
0376:                } catch (IOException e) {
0377:                    Exceptions.printStackTrace(e);
0378:                }
0379:
0380:                // If you invoke code completion while indexing is in progress, the
0381:                // completion job (which stores the caret offset) will be delayed until
0382:                // indexing is complete - potentially minutes later. When the job
0383:                // is finally run we need to make sure the caret position is still valid.
0384:                int length = doc.getLength();
0385:
0386:                if (caretOffset > length) {
0387:                    caretOffset = length;
0388:                }
0389:
0390:                return caretOffset;
0391:            }
0392:
0393:            /**
0394:             * Return the set of requires that are defined in this AST
0395:             * (no transitive closure though).
0396:             */
0397:            public static Set<String> getRequires(Node root) {
0398:                Set<String> requires = new HashSet<String>();
0399:                addRequires(root, requires);
0400:
0401:                return requires;
0402:            }
0403:
0404:            private static void addRequires(Node node, Set<String> requires) {
0405:                if (node.nodeId == NodeTypes.FCALLNODE) {
0406:                    // A method call
0407:                    String name = ((INameNode) node).getName();
0408:
0409:                    if (name.equals("require")) { // XXX Load too?
0410:
0411:                        Node argsNode = ((FCallNode) node).getArgsNode();
0412:
0413:                        if (argsNode instanceof  ListNode) {
0414:                            ListNode args = (ListNode) argsNode;
0415:
0416:                            if (args.size() > 0) {
0417:                                Node n = args.get(0);
0418:
0419:                                // For dynamically computed strings, we have n instanceof DStrNode
0420:                                // but I can't handle these anyway
0421:                                if (n instanceof  StrNode) {
0422:                                    ByteList require = ((StrNode) n).getValue();
0423:
0424:                                    if ((require != null)
0425:                                            && (require.length() > 0)) {
0426:                                        requires.add(require.toString());
0427:                                    }
0428:                                }
0429:                            }
0430:                        }
0431:                    }
0432:                } else if (node.nodeId == NodeTypes.MODULENODE
0433:                        || node.nodeId == NodeTypes.CLASSNODE
0434:                        || node.nodeId == NodeTypes.DEFNNODE
0435:                        || node.nodeId == NodeTypes.DEFSNODE) {
0436:                    // Only look for require statements at the top level
0437:                    return;
0438:                }
0439:
0440:                @SuppressWarnings("unchecked")
0441:                List<Node> list = node.childNodes();
0442:
0443:                for (Node child : list) {
0444:                    addRequires(child, requires);
0445:                }
0446:            }
0447:
0448:            /** Locate the method of the given name and arity */
0449:            public static MethodDefNode findMethod(Node node, String name,
0450:                    Arity arity) {
0451:                // Recursively search for methods or method calls that match the name and arity
0452:                if ((node.nodeId == NodeTypes.DEFNNODE || node.nodeId == NodeTypes.DEFSNODE)
0453:                        && ((MethodDefNode) node).getName().equals(name)) {
0454:                    Arity defArity = Arity.getDefArity(node);
0455:
0456:                    if (Arity.matches(arity, defArity)) {
0457:                        return (MethodDefNode) node;
0458:                    }
0459:                }
0460:
0461:                @SuppressWarnings("unchecked")
0462:                List<Node> list = node.childNodes();
0463:
0464:                for (Node child : list) {
0465:                    MethodDefNode match = findMethod(child, name, arity);
0466:
0467:                    if (match != null) {
0468:                        return match;
0469:                    }
0470:                }
0471:
0472:                return null;
0473:            }
0474:
0475:            public static MethodDefNode findMethodAtOffset(Node root, int offset) {
0476:                AstPath path = new AstPath(root, offset);
0477:                Iterator<Node> it = path.leafToRoot();
0478:
0479:                while (it.hasNext()) {
0480:                    Node node = it.next();
0481:
0482:                    if (node instanceof  MethodDefNode) {
0483:                        return (MethodDefNode) node;
0484:                    }
0485:                }
0486:
0487:                return null;
0488:            }
0489:
0490:            public static ClassNode findClassAtOffset(Node root, int offset) {
0491:                AstPath path = new AstPath(root, offset);
0492:                Iterator<Node> it = path.leafToRoot();
0493:
0494:                while (it.hasNext()) {
0495:                    Node node = it.next();
0496:
0497:                    if (node instanceof  ClassNode) {
0498:                        return (ClassNode) node;
0499:                    }
0500:                }
0501:
0502:                return null;
0503:            }
0504:
0505:            public static Node findLocalScope(Node node, AstPath path) {
0506:                Node method = findMethod(path);
0507:
0508:                if (method == null) {
0509:                    Iterator<Node> it = path.leafToRoot();
0510:                    while (it.hasNext()) {
0511:                        Node n = it.next();
0512:                        switch (n.nodeId) {
0513:                        case NodeTypes.DEFNNODE:
0514:                        case NodeTypes.DEFSNODE:
0515:                        case NodeTypes.CLASSNODE:
0516:                        case NodeTypes.SCLASSNODE:
0517:                        case NodeTypes.MODULENODE:
0518:                            return n;
0519:                        }
0520:                    }
0521:
0522:                    if (path.root() != null) {
0523:                        return path.root();
0524:                    }
0525:
0526:                    method = findBlock(path);
0527:                }
0528:
0529:                if (method == null) {
0530:                    method = path.leafParent();
0531:
0532:                    if (method.nodeId == NodeTypes.NEWLINENODE) {
0533:                        method = path.leafGrandParent();
0534:                    }
0535:
0536:                    if (method == null) {
0537:                        method = node;
0538:                    }
0539:                }
0540:
0541:                return method;
0542:            }
0543:
0544:            public static Node findDynamicScope(Node node, AstPath path) {
0545:                Node block = findBlock(path);
0546:
0547:                if (block == null) {
0548:                    // Use parent
0549:                    block = path.leafParent();
0550:
0551:                    if (block == null) {
0552:                        block = node;
0553:                    }
0554:                }
0555:
0556:                return block;
0557:            }
0558:
0559:            public static Node findBlock(AstPath path) {
0560:                // Find the most distant block node enclosing the given node (within
0561:                // the current method/class/module
0562:                Node candidate = null;
0563:                for (Node curr : path) {
0564:                    switch (curr.nodeId) {
0565:                    //case NodeTypes.BLOCKNODE:
0566:                    case NodeTypes.ITERNODE:
0567:                        candidate = curr;
0568:                        break;
0569:                    case NodeTypes.DEFNNODE:
0570:                    case NodeTypes.DEFSNODE:
0571:                    case NodeTypes.CLASSNODE:
0572:                    case NodeTypes.SCLASSNODE:
0573:                    case NodeTypes.MODULENODE:
0574:                        return candidate;
0575:                    }
0576:                }
0577:
0578:                return candidate;
0579:            }
0580:
0581:            public static MethodDefNode findMethod(AstPath path) {
0582:                // Find the closest block node enclosing the given node
0583:                for (Node curr : path) {
0584:                    if (curr.nodeId == NodeTypes.DEFNNODE
0585:                            || curr.nodeId == NodeTypes.DEFSNODE) {
0586:                        return (MethodDefNode) curr;
0587:                    }
0588:                    if (curr.nodeId == NodeTypes.CLASSNODE
0589:                            || curr.nodeId == NodeTypes.SCLASSNODE
0590:                            || curr.nodeId == NodeTypes.MODULENODE) {
0591:                        break;
0592:                    }
0593:                }
0594:
0595:                return null;
0596:            }
0597:
0598:            // XXX Shouldn't this go in the REVERSE direction? I might find
0599:            // a superclass here!
0600:            // XXX What about SClassNode?
0601:            public static ClassNode findClass(AstPath path) {
0602:                // Find the closest block node enclosing the given node
0603:                for (Node curr : path) {
0604:                    if (curr instanceof  ClassNode) {
0605:                        return (ClassNode) curr;
0606:                    }
0607:                }
0608:
0609:                return null;
0610:            }
0611:
0612:            public static IScopingNode findClassOrModule(AstPath path) {
0613:                // Find the closest block node enclosing the given node
0614:                for (Node curr : path) {
0615:                    // XXX What about SClassNodes?
0616:                    if (curr.nodeId == NodeTypes.CLASSNODE
0617:                            || curr.nodeId == NodeTypes.MODULENODE) {
0618:                        return (IScopingNode) curr;
0619:                    }
0620:                }
0621:
0622:                return null;
0623:            }
0624:
0625:            public static boolean isCall(Node node) {
0626:                return node.nodeId == NodeTypes.FCALLNODE
0627:                        || node.nodeId == NodeTypes.VCALLNODE
0628:                        || node.nodeId == NodeTypes.CALLNODE;
0629:            }
0630:
0631:            public static String getCallName(Node node) {
0632:                assert isCall(node);
0633:
0634:                if (node instanceof  INameNode) {
0635:                    return ((INameNode) node).getName();
0636:                }
0637:                assert false : node;
0638:
0639:                return null;
0640:            }
0641:
0642:            public static String getDefName(Node node) {
0643:                if (node instanceof  MethodDefNode) {
0644:                    return ((MethodDefNode) node).getName();
0645:                }
0646:                assert false : node;
0647:
0648:                return null;
0649:            }
0650:
0651:            public static ArgumentNode getDefNameNode(MethodDefNode node) {
0652:                return node.getNameNode();
0653:            }
0654:
0655:            public static boolean isConstructorMethod(MethodDefNode node) {
0656:                String name = node.getName();
0657:                if (name.equals("new") || name.equals("initialize")) { // NOI18N
0658:                    return true;
0659:                }
0660:
0661:                return false;
0662:            }
0663:
0664:            /** Find the direct child which is an ArgsNode, and pick out the argument names
0665:             * @param node The method definition node
0666:             * @param namesOnly If true, return only the parameter names for rest args and
0667:             *  blocks. If false, include "*" and "&".
0668:             */
0669:            @SuppressWarnings("unchecked")
0670:            public static List<String> getDefArgs(MethodDefNode node,
0671:                    boolean namesOnly) {
0672:                // TODO - do anything special about (&), blocks, argument lists (*), etc?
0673:                List<Node> nodes = (List<Node>) node.childNodes();
0674:
0675:                // TODO - use AstElement.getParameters?
0676:                for (Node c : nodes) {
0677:                    if (c instanceof  ArgsNode) {
0678:                        ArgsNode an = (ArgsNode) c;
0679:
0680:                        List<Node> args = (List<Node>) an.childNodes();
0681:                        List<String> parameters = new ArrayList<String>();
0682:
0683:                        for (Node arg : args) {
0684:                            if (arg instanceof  ListNode) {
0685:                                List<Node> args2 = (List<Node>) arg
0686:                                        .childNodes();
0687:
0688:                                for (Node arg2 : args2) {
0689:                                    if (arg2 instanceof  ArgumentNode) {
0690:                                        String name = ((ArgumentNode) arg2)
0691:                                                .getName();
0692:                                        parameters.add(name);
0693:                                    } else if (arg2 instanceof  LocalAsgnNode) {
0694:                                        String name = ((LocalAsgnNode) arg2)
0695:                                                .getName();
0696:                                        parameters.add(name);
0697:                                    }
0698:                                }
0699:                            }
0700:                        }
0701:
0702:                        // Rest args
0703:                        if (an.getRestArgNode() != null) {
0704:                            String name = an.getRestArgNode().getName();
0705:
0706:                            if (!namesOnly) {
0707:                                name = "*" + name;
0708:                            }
0709:
0710:                            parameters.add(name);
0711:                        }
0712:
0713:                        // Block args
0714:                        if (an.getBlockArgNode() != null) {
0715:                            String name = an.getBlockArgNode().getName();
0716:
0717:                            if (!namesOnly) {
0718:                                name = "&" + name;
0719:                            }
0720:
0721:                            parameters.add(name);
0722:                        }
0723:
0724:                        return parameters;
0725:                    }
0726:                }
0727:
0728:                return null;
0729:            }
0730:
0731:            public static String getDefSignature(MethodDefNode node) {
0732:                StringBuilder sb = new StringBuilder();
0733:                sb.append(getDefName(node));
0734:
0735:                List<String> args = getDefArgs(node, false);
0736:
0737:                if ((args != null) && (args.size() > 0)) {
0738:                    sb.append('(');
0739:
0740:                    Iterator<String> it = args.iterator();
0741:                    sb.append(it.next());
0742:
0743:                    while (it.hasNext()) {
0744:                        sb.append(',');
0745:                        sb.append(it.next());
0746:                    }
0747:
0748:                    sb.append(')');
0749:                }
0750:
0751:                return sb.toString();
0752:            }
0753:
0754:            /**
0755:             * Look for the caret offset in the parameter list; return the
0756:             * index of the parameter that contains it.
0757:             */
0758:            @SuppressWarnings("unchecked")
0759:            public static int findArgumentIndex(Node node, int offset) {
0760:                switch (node.nodeId) {
0761:                case NodeTypes.FCALLNODE: {
0762:                    Node argsNode = ((FCallNode) node).getArgsNode();
0763:
0764:                    return findArgumentIndex(argsNode, offset);
0765:                }
0766:                case NodeTypes.CALLNODE: {
0767:                    Node argsNode = ((CallNode) node).getArgsNode();
0768:
0769:                    return findArgumentIndex(argsNode, offset);
0770:                }
0771:                case NodeTypes.ARGSCATNODE: {
0772:                    ArgsCatNode acn = (ArgsCatNode) node;
0773:
0774:                    int index = findArgumentIndex(acn.getFirstNode(), offset);
0775:
0776:                    if (index != -1) {
0777:                        return index;
0778:                    }
0779:
0780:                    index = findArgumentIndex(acn.getSecondNode(), offset);
0781:
0782:                    if (index != -1) {
0783:                        // Add in arg count on the left
0784:                        return getConstantArgs(acn) + index;
0785:                    }
0786:
0787:                    ISourcePosition pos = node.getPosition();
0788:
0789:                    if ((offset >= pos.getStartOffset())
0790:                            && (offset <= pos.getEndOffset())) {
0791:                        return getConstantArgs(acn);
0792:                    }
0793:                }
0794:                case NodeTypes.HASHNODE:
0795:                    // Everything gets glommed into the same hash parameter offset
0796:                    return offset;
0797:                default:
0798:                    if (node instanceof  ListNode) {
0799:                        List<Node> children = node.childNodes();
0800:
0801:                        int prevEnd = Integer.MAX_VALUE;
0802:
0803:                        for (int index = 0; index < children.size(); index++) {
0804:                            Node child = children.get(index);
0805:                            if (child.nodeId == NodeTypes.HASHNODE) {
0806:                                // Invalid offsets - the hashnode often has the wrong offset
0807:                                OffsetRange range = AstUtilities
0808:                                        .getRange(child);
0809:                                if ((offset <= range.getEnd())
0810:                                        && ((offset >= prevEnd) || (offset >= range
0811:                                                .getStart()))) {
0812:                                    return index;
0813:                                }
0814:
0815:                                prevEnd = range.getEnd();
0816:                            } else {
0817:                                ISourcePosition pos = child.getPosition();
0818:                                if ((offset <= pos.getEndOffset())
0819:                                        && ((offset >= prevEnd) || (offset >= pos
0820:                                                .getStartOffset()))) {
0821:                                    return index;
0822:                                }
0823:
0824:                                prevEnd = pos.getEndOffset();
0825:                            }
0826:
0827:                        }
0828:
0829:                        // Caret -inside- empty parentheses?
0830:                        ISourcePosition pos = node.getPosition();
0831:
0832:                        if ((offset > pos.getStartOffset())
0833:                                && (offset < pos.getEndOffset())) {
0834:                            return 0;
0835:                        }
0836:                    } else {
0837:                        ISourcePosition pos = node.getPosition();
0838:
0839:                        if ((offset >= pos.getStartOffset())
0840:                                && (offset <= pos.getEndOffset())) {
0841:                            return 0;
0842:                        }
0843:                    }
0844:
0845:                    return -1;
0846:                }
0847:            }
0848:
0849:            /** Utility method used by findArgumentIndex: count the constant number of
0850:             * arguments in a parameter list before the argscatnode */
0851:            private static int getConstantArgs(ArgsCatNode acn) {
0852:                Node node = acn.getFirstNode();
0853:
0854:                if (node instanceof  ListNode) {
0855:                    List children = node.childNodes();
0856:
0857:                    return children.size();
0858:                } else {
0859:                    return 1;
0860:                }
0861:            }
0862:
0863:            /**
0864:             * Return true iff the given call note can be considered a valid call of the given method.
0865:             */
0866:            public static boolean isCallFor(Node call, Arity callArity,
0867:                    Node method) {
0868:                assert isCall(call);
0869:                assert method instanceof  MethodDefNode;
0870:
0871:                // Simple call today...
0872:                return getDefName(method).equals(getCallName(call))
0873:                        && Arity.matches(callArity, Arity.getDefArity(method));
0874:            }
0875:
0876:            // TODO: use the structure analyzer data for more accurate traversal?
0877:            /** For the given signature, locating the corresponding Node within the tree that
0878:             * it corresponds to */
0879:            public static Node findBySignature(Node root, String signature) {
0880:                String originalSig = signature;
0881:
0882:                //String name = signature.split("(::)")
0883:                // Find next name we're looking for
0884:                String name = getNextSigComponent(signature);
0885:                signature = signature.substring(name.length());
0886:
0887:                Node node = findBySignature(root, signature, name);
0888:
0889:                // Handle top level methods
0890:                if (node == null && originalSig.startsWith("Object#")) {
0891:                    // Just look for top level method definitions instead
0892:                    originalSig = originalSig.substring(originalSig
0893:                            .indexOf('#') + 1);
0894:                    name = getNextSigComponent(signature);
0895:                    signature = originalSig.substring(name.length());
0896:
0897:                    node = findBySignature(root, signature, name);
0898:                }
0899:
0900:                return node;
0901:            }
0902:
0903:            // For a signature of the form Foo::Bar#baz(arg1,arg2,...)
0904:            // pull out the next component; in the above, successively return
0905:            // "Foo", "Bar", "baz", etc.
0906:            private static String getNextSigComponent(String signature) {
0907:                StringBuilder sb = new StringBuilder();
0908:                int i = 0;
0909:                int n = signature.length();
0910:
0911:                // Skip leading separators
0912:                for (; i < n; i++) {
0913:                    char c = signature.charAt(i);
0914:
0915:                    if ((c == '#') || (c == ':') || (c == '(')) {
0916:                        continue;
0917:                    }
0918:
0919:                    break;
0920:                }
0921:
0922:                // Add the name
0923:                for (; i < n; i++) {
0924:                    char c = signature.charAt(i);
0925:
0926:                    if ((c == '#') || (c == ':') || (c == '(')) {
0927:                        break;
0928:                    }
0929:
0930:                    sb.append(c);
0931:                }
0932:
0933:                return sb.toString();
0934:            }
0935:
0936:            private static Node findBySignature(Node node, String signature,
0937:                    String name) {
0938:                switch (node.nodeId) {
0939:                case NodeTypes.INSTASGNNODE:
0940:                    if (name.charAt(0) == '@') {
0941:                        String n = ((INameNode) node).getName();
0942:                        //if (name.regionMatches(1, n, 0, n.length())) {
0943:                        if (name.equals(n)) {
0944:                            return node;
0945:                        }
0946:                    }
0947:                    break;
0948:                case NodeTypes.CLASSVARDECLNODE:
0949:                case NodeTypes.CLASSVARASGNNODE:
0950:                    if (name.startsWith("@@")) {
0951:                        String n = ((INameNode) node).getName();
0952:                        //if (name.regionMatches(2, n, 0, n.length())) {
0953:                        if (name.equals(n)) {
0954:                            return node;
0955:                        }
0956:                    }
0957:                    break;
0958:
0959:                case NodeTypes.DEFNNODE:
0960:                case NodeTypes.DEFSNODE:
0961:                    boolean lookingForMethod = (Character.isLowerCase(name
0962:                            .charAt(0)));
0963:                    if (lookingForMethod
0964:                            && name.equals(AstUtilities.getDefName(node))) {
0965:                        // See if the parameter list matches
0966:                        // XXX TODO
0967:                        List<String> parameters = getDefArgs(
0968:                                (MethodDefNode) node, false);
0969:
0970:                        if ((signature.length() == 0)
0971:                                && ((parameters == null) || (parameters.size() == 0))) {
0972:                            // No args
0973:                            return node;
0974:                        } else if (signature.length() != 0) {
0975:                            assert signature.charAt(0) == '(';
0976:
0977:                            String argList = signature.substring(1, signature
0978:                                    .length() - 1);
0979:                            String[] args = argList.split(",");
0980:
0981:                            if (args.length == parameters.size()) {
0982:                                // Should I enforce equality here?
0983:                                boolean equal = true;
0984:
0985:                                for (int i = 0; i < args.length; i++) {
0986:                                    if (!args[i].equals(parameters.get(i))) {
0987:                                        equal = false;
0988:
0989:                                        break;
0990:                                    }
0991:                                }
0992:
0993:                                if (equal) {
0994:                                    return node;
0995:                                }
0996:                            }
0997:                        }
0998:                    } else if (isAttr(node)) {
0999:                        SymbolNode[] symbols = getAttrSymbols(node);
1000:                        for (SymbolNode sym : symbols) {
1001:                            if (name.equals(sym.getName())) {
1002:                                return node;
1003:                            }
1004:                        }
1005:                    }
1006:                    break;
1007:
1008:                case NodeTypes.CLASSNODE:
1009:                case NodeTypes.MODULENODE: {
1010:                    Colon3Node c3n = ((IScopingNode) node).getCPath();
1011:
1012:                    if (c3n instanceof  Colon2Node) {
1013:                        String fqn = getFqn((Colon2Node) c3n);
1014:
1015:                        if (fqn.startsWith(name)
1016:                                && signature.startsWith(fqn.substring(name
1017:                                        .length()))) {
1018:                            signature = signature.substring(fqn.substring(
1019:                                    name.length()).length());
1020:                            name = getNextSigComponent(signature);
1021:
1022:                            if (name.length() == 0) {
1023:                                // The signature points to a class (or module) - just return it
1024:                                return node;
1025:                            }
1026:
1027:                            int index = signature.indexOf(name);
1028:                            assert index != -1;
1029:                            signature = signature.substring(index
1030:                                    + name.length());
1031:                        }
1032:                    } else if (name.equals(AstUtilities
1033:                            .getClassOrModuleName(((IScopingNode) node)))) {
1034:                        name = getNextSigComponent(signature);
1035:
1036:                        if (name.length() == 0) {
1037:                            // The signature points to a class (or module) - just return it
1038:                            return node;
1039:                        }
1040:
1041:                        int index = signature.indexOf(name);
1042:                        assert index != -1;
1043:                        signature = signature.substring(index + name.length());
1044:                    }
1045:                    break;
1046:                }
1047:                case NodeTypes.SCLASSNODE:
1048:                    Node receiver = ((SClassNode) node).getReceiverNode();
1049:                    String rn = null;
1050:
1051:                    if (receiver instanceof  Colon2Node) {
1052:                        // TODO - check to see if we qualify
1053:                        rn = ((Colon2Node) receiver).getName();
1054:                    } else if (receiver instanceof  ConstNode) {
1055:                        rn = ((ConstNode) receiver).getName();
1056:                    } // else: some other type of singleton class definition, like class << foo
1057:
1058:                    if (rn != null) {
1059:                        if (name.equals(rn)) {
1060:                            name = getNextSigComponent(signature);
1061:
1062:                            if (name.length() == 0) {
1063:                                // The signature points to a class (or module) - just return it
1064:                                return node;
1065:                            }
1066:
1067:                            int index = signature.indexOf(name);
1068:                            assert index != -1;
1069:                            signature = signature.substring(index
1070:                                    + name.length());
1071:                        }
1072:                    }
1073:                    break;
1074:                }
1075:                @SuppressWarnings("unchecked")
1076:                List<Node> list = node.childNodes();
1077:
1078:                for (Node child : list) {
1079:                    Node match = findBySignature(child, signature, name);
1080:
1081:                    if (match != null) {
1082:                        return match;
1083:                    }
1084:                }
1085:
1086:                return null;
1087:            }
1088:
1089:            /** Return true iff the given node contains the given offset */
1090:            public static boolean containsOffset(Node node, int offset) {
1091:                ISourcePosition pos = node.getPosition();
1092:
1093:                return ((offset >= pos.getStartOffset()) && (offset <= pos
1094:                        .getEndOffset()));
1095:            }
1096:
1097:            /**
1098:             * Return a range that matches the given node's source buffer range
1099:             */
1100:            @SuppressWarnings("unchecked")
1101:            public static OffsetRange getRange(Node node) {
1102:                if (node.nodeId == NodeTypes.NOTNODE) {
1103:                    ISourcePosition pos = node.getPosition();
1104:                    // "unless !(x < 5)" gives a not-node with wrong offsets - starts
1105:                    // with ! but doesn't include the closing )
1106:                    List<Node> list = node.childNodes();
1107:                    if (list != null && list.size() > 0) {
1108:                        Node first = list.get(0);
1109:                        if (first.nodeId == NodeTypes.NEWLINENODE) {
1110:                            OffsetRange range = getRange(first);
1111:                            return new OffsetRange(pos.getStartOffset(), range
1112:                                    .getEnd());
1113:                        }
1114:                    }
1115:                    return new OffsetRange(pos.getStartOffset(), pos
1116:                            .getEndOffset());
1117:                } else if (node.nodeId == NodeTypes.HASHNODE) {
1118:                    // Workaround for incorrect JRuby AST offsets for hashnodes :
1119:                    //   render :action => 'list'
1120:                    // has wrong argument offsets, which we want to correct.
1121:                    // Just adopt the start offset of its first child (if any) and
1122:                    // the end offset of its last child (if any)
1123:                    List<Node> list = node.childNodes();
1124:                    if (list != null && list.size() > 0) {
1125:                        int start = list.get(0).getPosition().getStartOffset();
1126:                        int end = list.get(list.size() - 1).getPosition()
1127:                                .getEndOffset();
1128:                        return new OffsetRange(start, end);
1129:                    } else {
1130:                        ISourcePosition pos = node.getPosition();
1131:                        return new OffsetRange(pos.getStartOffset(), pos
1132:                                .getEndOffset());
1133:                    }
1134:                } else {
1135:                    ISourcePosition pos = node.getPosition();
1136:                    return new OffsetRange(pos.getStartOffset(), pos
1137:                            .getEndOffset());
1138:                }
1139:            }
1140:
1141:            /**
1142:             * Return a range that matches the lvalue for an assignment. The node must be namable.
1143:             */
1144:            public static OffsetRange getLValueRange(AssignableNode node) {
1145:                assert node instanceof  INameNode;
1146:
1147:                ISourcePosition pos = node.getPosition();
1148:                OffsetRange range = new OffsetRange(pos.getStartOffset(), pos
1149:                        .getStartOffset()
1150:                        + ((INameNode) node).getName().length());
1151:
1152:                return range;
1153:            }
1154:
1155:            public static OffsetRange getNameRange(Node node) {
1156:                if (node instanceof  AssignableNode) {
1157:                    return getLValueRange((AssignableNode) node);
1158:                } else if (node instanceof  MethodDefNode) {
1159:                    return getFunctionNameRange(node);
1160:                } else if (isCall(node)) {
1161:                    return getCallRange(node);
1162:                } else if (node instanceof  ClassNode) {
1163:                    // TODO - try to pull out the constnode or colon2node holding the class name,
1164:                    // and return it!
1165:                    Colon3Node c3n = ((ClassNode) node).getCPath();
1166:                    if (c3n != null) {
1167:                        return getRange(c3n);
1168:                    } else {
1169:                        return getRange(node);
1170:                    }
1171:                } else if (node instanceof  ModuleNode) {
1172:                    // TODO - try to pull out the constnode or colon2node holding the class name,
1173:                    // and return it!
1174:                    Colon3Node c3n = ((ModuleNode) node).getCPath();
1175:                    if (c3n != null) {
1176:                        return getRange(c3n);
1177:                    } else {
1178:                        return getRange(node);
1179:                    }
1180:                    //        } else if (node instanceof SClassNode) {
1181:                    //            // TODO - try to pull out the constnode or colon2node holding the class name,
1182:                    //            // and return it!
1183:                    //            Colon3Node c3n = ((SClassNode)node).getCPath();
1184:                    //            if (c3n != null) {
1185:                    //                return getRange(c3n);
1186:                    //            } else {
1187:                    //                return getRange(node);
1188:                    //            }
1189:                } else {
1190:                    return getRange(node);
1191:                }
1192:            }
1193:
1194:            /** For CallNodes, the offset range for the AST node includes the entire parameter list.
1195:             *  We want ONLY the actual call/operator name. So compute that on our own.
1196:             */
1197:            public static OffsetRange getCallRange(Node node) {
1198:                ISourcePosition pos = node.getPosition();
1199:                int start = pos.getStartOffset();
1200:                int end = pos.getEndOffset();
1201:                assert isCall(node);
1202:                assert node instanceof  INameNode;
1203:
1204:                if (node instanceof  CallNode) {
1205:                    // A call of the form Foo.bar. "bar" is the CallNode, "Foo" is the ReceiverNode.
1206:                    // Here I'm only handling named nodes; there may be others
1207:                    Node receiver = ((CallNode) node).getReceiverNode();
1208:
1209:                    if (receiver != null) {
1210:                        start = receiver.getPosition().getEndOffset() + 1; // end of "Foo::bar" + "."
1211:                    }
1212:                }
1213:
1214:                if (node instanceof  INameNode) {
1215:                    end = start + ((INameNode) node).getName().length();
1216:                }
1217:
1218:                return new OffsetRange(start, end);
1219:            }
1220:
1221:            @SuppressWarnings("unchecked")
1222:            public static OffsetRange getFunctionNameRange(Node node) {
1223:                // TODO - enforce MethodDefNode and call getNameNode on it!
1224:                for (Node child : (List<Node>) node.childNodes()) {
1225:                    if (child instanceof  ArgumentNode) {
1226:                        OffsetRange range = AstUtilities.getRange(child);
1227:
1228:                        return range;
1229:                    }
1230:                }
1231:
1232:                if (node instanceof  MethodDefNode) {
1233:                    for (Node child : (List<Node>) node.childNodes()) {
1234:                        if (child instanceof  ConstNode) {
1235:                            ISourcePosition pos = child.getPosition();
1236:                            int end = pos.getEndOffset();
1237:                            int start;
1238:
1239:                            if (INCLUDE_DEFS_PREFIX) {
1240:                                start = pos.getStartOffset();
1241:                            } else {
1242:                                start = end + 1;
1243:                            }
1244:
1245:                            // TODO - look at the source buffer and tweak offset if it's wrong
1246:                            // This assumes we have a single constant node, followed by a dot, followed by the name
1247:                            end = end + 1
1248:                                    + AstUtilities.getDefName(node).length(); // +1: "."
1249:
1250:                            OffsetRange range = new OffsetRange(start, end);
1251:
1252:                            return range;
1253:                        }
1254:                    }
1255:                }
1256:
1257:                return OffsetRange.NONE;
1258:            }
1259:
1260:            /**
1261:             * Return the OffsetRange for an AliasNode that represents the new name portion.
1262:             */
1263:            public static OffsetRange getAliasNewRange(AliasNode node) {
1264:                // XXX I don't know where the old and new names are since the user COULD
1265:                // have used more than one whitespace character for separation. For now I'll
1266:                // just have to assume it's the normal case with one space:  alias new old.
1267:                // I -could- use the getPosition.getEndOffset() to see if this looks like it's
1268:                // the case (e.g. node length != "alias ".length + old.length+new.length+1).
1269:                // In this case I could go peeking in the source buffer to see where the
1270:                // spaces are - between alias and the first word or between old and new. XXX.
1271:                ISourcePosition pos = node.getPosition();
1272:
1273:                int newStart = pos.getStartOffset() + 6; // 6: "alias ".length()
1274:
1275:                return new OffsetRange(newStart, newStart
1276:                        + node.getNewName().length());
1277:            }
1278:
1279:            /**
1280:             * Return the OffsetRange for an AliasNode that represents the old name portion.
1281:             */
1282:            public static OffsetRange getAliasOldRange(AliasNode node) {
1283:                // XXX I don't know where the old and new names are since the user COULD
1284:                // have used more than one whitespace character for separation. For now I'll
1285:                // just have to assume it's the normal case with one space:  alias new old.
1286:                // I -could- use the getPosition.getEndOffset() to see if this looks like it's
1287:                // the case (e.g. node length != "alias ".length + old.length+new.length+1).
1288:                // In this case I could go peeking in the source buffer to see where the
1289:                // spaces are - between alias and the first word or between old and new. XXX.
1290:                ISourcePosition pos = node.getPosition();
1291:
1292:                int oldStart = pos.getStartOffset() + 6
1293:                        + node.getNewName().length() + 1; // 6: "alias ".length; 1: " ".length
1294:
1295:                return new OffsetRange(oldStart, oldStart
1296:                        + node.getOldName().length());
1297:            }
1298:
1299:            public static String getClassOrModuleName(IScopingNode node) {
1300:                return ((INameNode) node.getCPath()).getName();
1301:            }
1302:
1303:            public static List<ClassNode> getClasses(Node root) {
1304:                // I would like to use a visitor for this, but it's not
1305:                // working - I get NPE's within DefaultIteratorVisitor
1306:                // on valid ASTs, and I see it's not used heavily in JRuby,
1307:                // so I'm not doing it this way for now.
1308:                //final List<ClassNode> classes = new ArrayList<ClassNode>();
1309:                //// There could be multiple Class definitions for this
1310:                //// same class, and (empirically) rdoc shows the documentation
1311:                //// for the last declaration.
1312:                //NodeVisitor findClasses = new AbstractVisitor() {
1313:                //    public Instruction visitClassNode(ClassNode node) {
1314:                //        classes.add(node);
1315:                //        return visitNode(node);
1316:                //    }
1317:                //
1318:                //    protected Instruction visitNode(Node iVisited) {
1319:                //        return null;
1320:                //    }
1321:                //};
1322:                //new DefaultIteratorVisitor(findClasses).visitRootNode((RootNode)parseResult.getRootNode());
1323:                List<ClassNode> classes = new ArrayList<ClassNode>();
1324:                addClasses(root, classes);
1325:
1326:                return classes;
1327:            }
1328:
1329:            private static void addClasses(Node node, List<ClassNode> classes) {
1330:                if (node instanceof  ClassNode) {
1331:                    classes.add((ClassNode) node);
1332:                }
1333:
1334:                @SuppressWarnings("unchecked")
1335:                List<Node> list = node.childNodes();
1336:
1337:                for (Node child : list) {
1338:                    addClasses(child, classes);
1339:                }
1340:            }
1341:
1342:            private static void addAncestorParents(Node node, StringBuilder sb) {
1343:                if (node instanceof  Colon2Node) {
1344:                    Colon2Node c2n = (Colon2Node) node;
1345:                    addAncestorParents(c2n.getLeftNode(), sb);
1346:
1347:                    if ((sb.length() > 0)
1348:                            && (sb.charAt(sb.length() - 1) != ':')) {
1349:                        sb.append("::");
1350:                    }
1351:
1352:                    sb.append(c2n.getName());
1353:                } else if (node instanceof  INameNode) {
1354:                    if ((sb.length() > 0)
1355:                            && (sb.charAt(sb.length() - 1) != ':')) {
1356:                        sb.append("::");
1357:                    }
1358:
1359:                    sb.append(((INameNode) node).getName());
1360:                }
1361:            }
1362:
1363:            public static String getFqn(Colon2Node c2n) {
1364:                StringBuilder sb = new StringBuilder();
1365:
1366:                addAncestorParents(c2n, sb);
1367:
1368:                return sb.toString();
1369:            }
1370:
1371:            public static String getSuperclass(ClassNode clz) {
1372:                StringBuilder sb = new StringBuilder();
1373:
1374:                if (clz.getSuperNode() != null) {
1375:                    addAncestorParents(clz.getSuperNode(), sb);
1376:
1377:                    return sb.toString();
1378:                }
1379:
1380:                return null;
1381:            }
1382:
1383:            /** Compute the module/class name for the given node path */
1384:            public static String getFqnName(AstPath path) {
1385:                StringBuilder sb = new StringBuilder();
1386:
1387:                Iterator<Node> it = path.rootToLeaf();
1388:
1389:                while (it.hasNext()) {
1390:                    Node node = it.next();
1391:
1392:                    if (node instanceof  ModuleNode || node instanceof  ClassNode) {
1393:                        Colon3Node cpath = ((IScopingNode) node).getCPath();
1394:
1395:                        if (cpath == null) {
1396:                            continue;
1397:                        }
1398:
1399:                        if (sb.length() > 0) {
1400:                            sb.append("::"); // NOI18N
1401:                        }
1402:
1403:                        if (cpath instanceof  Colon2Node) {
1404:                            sb.append(getFqn((Colon2Node) cpath));
1405:                        } else {
1406:                            sb.append(cpath.getName());
1407:                        }
1408:                    }
1409:                }
1410:
1411:                return sb.toString();
1412:            }
1413:
1414:            public static boolean isAttr(Node node) {
1415:                if (!(node instanceof  FCallNode)) {
1416:                    return false;
1417:                }
1418:
1419:                String name = ((INameNode) node).getName();
1420:
1421:                if (name.startsWith("attr")) { // NOI18N
1422:
1423:                    if ("attr".equals(name)
1424:                            || "attr_reader".equals(name)
1425:                            || // NOI18N
1426:                            "attr_accessor".equals(name)
1427:                            || "attr_writer".equals(name)
1428:                            || // NOI18N
1429:                            // Rails: Special definitions which builds methods that have actual fields
1430:                            // backing the attribute. Important to include these since they're
1431:                            // used for key Rails members like headers, session, etc.
1432:                            "attr_internal".equals(name)
1433:                            || "attr_internal_reader".equals(name)
1434:                            || "attr_internal_writer".equals(name) || // NOI18N
1435:                            "attr_internal_accessor".equals(name)) { // NOI18N
1436:
1437:                        return true;
1438:                    }
1439:                }
1440:
1441:                return false;
1442:            }
1443:
1444:            @SuppressWarnings("unchecked")
1445:            public static SymbolNode[] getAttrSymbols(Node node) {
1446:                assert isAttr(node);
1447:
1448:                List<Node> list = node.childNodes();
1449:
1450:                for (Node child : list) {
1451:                    if (child instanceof  ListNode) {
1452:                        List<Node> symbols = (List<Node>) child.childNodes();
1453:                        List<SymbolNode> symbolList = new ArrayList<SymbolNode>(
1454:                                symbols.size());
1455:
1456:                        for (Node symbol : symbols) {
1457:                            if (symbol instanceof  SymbolNode) {
1458:                                symbolList.add((SymbolNode) symbol);
1459:                            }
1460:                        }
1461:
1462:                        return symbolList.toArray(new SymbolNode[symbolList
1463:                                .size()]);
1464:                    }
1465:                }
1466:
1467:                return new SymbolNode[0];
1468:            }
1469:
1470:            public static RubyParseResult getParseResult(CompilationInfo info) {
1471:                ParserResult result = info.getEmbeddedResult(
1472:                        RubyMimeResolver.RUBY_MIME_TYPE, 0);
1473:
1474:                if (result == null) {
1475:                    return null;
1476:                } else {
1477:                    return ((RubyParseResult) result);
1478:                }
1479:            }
1480:
1481:            public static Node getRoot(CompilationInfo info) {
1482:                return getRoot(info, RubyMimeResolver.RUBY_MIME_TYPE);
1483:            }
1484:
1485:            public static Node getRoot(CompilationInfo info, String mimeType) {
1486:                ParserResult result = info.getEmbeddedResult(mimeType, 0);
1487:
1488:                if (result == null) {
1489:                    return null;
1490:                }
1491:
1492:                return getRoot(result);
1493:            }
1494:
1495:            public static Node getRoot(ParserResult r) {
1496:                assert r instanceof  RubyParseResult;
1497:
1498:                RubyParseResult result = (RubyParseResult) r;
1499:
1500:                return result.getRootNode();
1501:            }
1502:
1503:            /**
1504:             * Get the private and protected methods in the given class
1505:             */
1506:            public static void findPrivateMethods(Node clz,
1507:                    Set<Node> protectedMethods, Set<Node> privateMethods) {
1508:                Set<String> publicMethodSymbols = new HashSet<String>();
1509:                Set<String> protectedMethodSymbols = new HashSet<String>();
1510:                Set<String> privateMethodSymbols = new HashSet<String>();
1511:                Set<Node> publicMethods = new HashSet<Node>();
1512:
1513:                @SuppressWarnings("unchecked")
1514:                List<Node> list = clz.childNodes();
1515:
1516:                Modifier access = Modifier.PUBLIC;
1517:
1518:                for (Node child : list) {
1519:                    access = getMethodAccess(child, access,
1520:                            publicMethodSymbols, protectedMethodSymbols,
1521:                            privateMethodSymbols, publicMethods,
1522:                            protectedMethods, privateMethods);
1523:                }
1524:
1525:                // Can't just return private methods directly, since sometimes you can
1526:                // specify that a particular method is public before we know about it,
1527:                // so I can't just remove it from the known private list when I see the
1528:                // access modifier
1529:                privateMethodSymbols.removeAll(publicMethodSymbols);
1530:                protectedMethodSymbols.removeAll(publicMethodSymbols);
1531:
1532:                // Should I worry about private foo;  protected :foo ?
1533:                // Seems unlikely somebody would do that... I guess
1534:                // I could do privateMethodSymbols.removeAll(protectedMethodSymbols) etc.
1535:                //privateMethodSymbols.removeAll(protectedMethodSymbols);
1536:                //protectedMethodSymbols.removeAll(privateMethodSymbols);
1537:
1538:                // Add all methods known to be private into the private node set
1539:                for (String name : privateMethodSymbols) {
1540:                    for (Node n : publicMethods) {
1541:                        if (name.equals(AstUtilities.getDefName(n))) {
1542:                            privateMethods.add(n);
1543:                        }
1544:                    }
1545:                }
1546:
1547:                for (String name : protectedMethodSymbols) {
1548:                    for (Node n : publicMethods) {
1549:                        if (name.equals(AstUtilities.getDefName(n))) {
1550:                            protectedMethods.add(n);
1551:                        }
1552:                    }
1553:                }
1554:            }
1555:
1556:            /**
1557:             * @todo Should I really recurse into classes? If I have nested classes private
1558:             *  methods ther shouldn't be included for the parent!
1559:             *
1560:             * @param access The "current" known access level (PUBLIC, PROTECTED or PRIVATE)
1561:             * @return the access level to continue with at this syntactic level
1562:             */
1563:            @SuppressWarnings("unchecked")
1564:            private static Modifier getMethodAccess(Node node, Modifier access,
1565:                    Set<String> publicMethodSymbols,
1566:                    Set<String> protectedMethodSymbols,
1567:                    Set<String> privateMethodSymbols, Set<Node> publicMethods,
1568:                    Set<Node> protectedMethods, Set<Node> privateMethods) {
1569:                if (node instanceof  MethodDefNode) {
1570:                    if (access == Modifier.PRIVATE) {
1571:                        privateMethods.add(node);
1572:                    } else if (access == Modifier.PUBLIC) {
1573:                        publicMethods.add(node);
1574:                    } else if (access == Modifier.PROTECTED) {
1575:                        protectedMethods.add(node);
1576:                    }
1577:
1578:                    // XXX Can I have nested method definitions? If so I may have to continue here
1579:                    return access;
1580:                } else if (node instanceof  VCallNode
1581:                        || node instanceof  FCallNode) {
1582:                    String name = ((INameNode) node).getName();
1583:
1584:                    if ("private".equals(name)) {
1585:                        // TODO - see if it has arguments, if it does - it's just a single
1586:                        // method defined to be private
1587:                        // Iterate over arguments and add symbols...
1588:                        if (Arity.callHasArguments(node)) {
1589:                            List<Node> params = (List<Node>) node.childNodes();
1590:
1591:                            for (Node param : params) {
1592:                                if (param instanceof  ListNode) {
1593:                                    List<Node> params2 = (List<Node>) param
1594:                                            .childNodes();
1595:
1596:                                    for (Node param2 : params2) {
1597:                                        if (param2 instanceof  SymbolNode) {
1598:                                            String symbol = ((SymbolNode) param2)
1599:                                                    .getName();
1600:                                            privateMethodSymbols.add(symbol);
1601:                                        }
1602:                                    }
1603:                                }
1604:                            }
1605:                        } else {
1606:                            access = Modifier.PRIVATE;
1607:                        }
1608:
1609:                        return access;
1610:                    } else if ("protected".equals(name)) {
1611:                        // TODO - see if it has arguments, if it does - it's just a single
1612:                        // method defined to be private
1613:                        // Iterate over arguments and add symbols...
1614:                        if (Arity.callHasArguments(node)) {
1615:                            List<Node> params = (List<Node>) node.childNodes();
1616:
1617:                            for (Node param : params) {
1618:                                if (param instanceof  ListNode) {
1619:                                    List<Node> params2 = (List<Node>) param
1620:                                            .childNodes();
1621:
1622:                                    for (Node param2 : params2) {
1623:                                        if (param2 instanceof  SymbolNode) {
1624:                                            String symbol = ((SymbolNode) param2)
1625:                                                    .getName();
1626:                                            protectedMethodSymbols.add(symbol);
1627:                                        }
1628:                                    }
1629:                                }
1630:                            }
1631:                        } else {
1632:                            access = Modifier.PROTECTED;
1633:                        }
1634:
1635:                        return access;
1636:                    } else if ("public".equals(name)) {
1637:                        if (!Arity.callHasArguments(node)) {
1638:                            access = Modifier.PUBLIC;
1639:
1640:                            return access;
1641:                        } else {
1642:                            List<Node> params = (List<Node>) node.childNodes();
1643:
1644:                            for (Node param : params) {
1645:                                if (param instanceof  ListNode) {
1646:                                    List<Node> params2 = (List<Node>) param
1647:                                            .childNodes();
1648:
1649:                                    for (Node param2 : params2) {
1650:                                        if (param2 instanceof  SymbolNode) {
1651:                                            String symbol = ((SymbolNode) param2)
1652:                                                    .getName();
1653:                                            publicMethodSymbols.add(symbol);
1654:                                        }
1655:                                    }
1656:                                }
1657:                            }
1658:                        }
1659:                    }
1660:
1661:                    return access;
1662:                } else if (node instanceof  ClassNode
1663:                        || node instanceof  ModuleNode) {
1664:                    return access;
1665:                }
1666:
1667:                @SuppressWarnings("unchecked")
1668:                List<Node> list = node.childNodes();
1669:
1670:                for (Node child : list) {
1671:                    access = getMethodAccess(child, access,
1672:                            publicMethodSymbols, protectedMethodSymbols,
1673:                            privateMethodSymbols, publicMethods,
1674:                            protectedMethods, privateMethods);
1675:                }
1676:
1677:                return access;
1678:            }
1679:
1680:            /**
1681:             * Get the method name for the given offset - or null if it cannot be found. This
1682:             * will initiate a new parse job if necessary.
1683:             */
1684:            public static String getMethodName(FileObject fo, final int offset) {
1685:                SourceModel js = SourceModelFactory.getInstance().getModel(fo);
1686:
1687:                if (js == null) {
1688:                    return null;
1689:                }
1690:
1691:                if (js.isScanInProgress()) {
1692:                    return null;
1693:                }
1694:
1695:                final String[] result = new String[1];
1696:
1697:                try {
1698:                    js.runUserActionTask(
1699:                            new CancellableTask<CompilationInfo>() {
1700:                                public void cancel() {
1701:                                }
1702:
1703:                                public void run(CompilationInfo info) {
1704:                                    org.jruby.ast.Node root = AstUtilities
1705:                                            .getRoot(info);
1706:
1707:                                    if (root == null) {
1708:                                        return;
1709:                                    }
1710:
1711:                                    org.jruby.ast.MethodDefNode method = AstUtilities
1712:                                            .findMethodAtOffset(root, offset);
1713:
1714:                                    if (method == null) {
1715:                                        // It's possible the user had the caret on a line
1716:                                        // that includes a method that isn't actually inside
1717:                                        // the method block - such as the beginning of the
1718:                                        // "def" line, or the end of a line after "end".
1719:                                        // The latter isn't very likely, but the former can
1720:                                        // happen, so let's check the method bodies at the
1721:                                        // end of the current line
1722:                                        try {
1723:                                            BaseDocument doc = (BaseDocument) info
1724:                                                    .getDocument();
1725:                                            int endOffset = Utilities
1726:                                                    .getRowEnd(doc, offset);
1727:
1728:                                            if (endOffset != offset) {
1729:                                                method = AstUtilities
1730:                                                        .findMethodAtOffset(
1731:                                                                root, endOffset);
1732:                                            }
1733:                                        } catch (BadLocationException ble) {
1734:                                            Exceptions.printStackTrace(ble);
1735:                                        } catch (IOException ioe) {
1736:                                            Exceptions.printStackTrace(ioe);
1737:                                        }
1738:                                    }
1739:
1740:                                    if (method != null) {
1741:                                        result[0] = method.getName();
1742:                                    }
1743:                                }
1744:                            }, true);
1745:                } catch (IOException ioe) {
1746:                    Exceptions.printStackTrace(ioe);
1747:                }
1748:
1749:                return result[0];
1750:            }
1751:
1752:            public static int findOffset(FileObject fo, final String methodName) {
1753:                SourceModel js = SourceModelFactory.getInstance().getModel(fo);
1754:
1755:                if (js == null) {
1756:                    return -1;
1757:                }
1758:
1759:                if (js.isScanInProgress()) {
1760:                    return -1;
1761:                }
1762:
1763:                final int[] result = new int[1];
1764:                result[0] = -1;
1765:
1766:                try {
1767:                    js.runUserActionTask(
1768:                            new CancellableTask<CompilationInfo>() {
1769:                                public void cancel() {
1770:                                }
1771:
1772:                                public void run(CompilationInfo info) {
1773:                                    org.jruby.ast.Node root = AstUtilities
1774:                                            .getRoot(info);
1775:
1776:                                    if (root == null) {
1777:                                        return;
1778:                                    }
1779:
1780:                                    org.jruby.ast.Node method = AstUtilities
1781:                                            .findMethod(root, methodName,
1782:                                                    Arity.UNKNOWN);
1783:
1784:                                    if (method != null) {
1785:                                        int startOffset = method.getPosition()
1786:                                                .getStartOffset();
1787:                                        result[0] = startOffset;
1788:                                    }
1789:                                }
1790:                            }, true);
1791:                } catch (IOException ioe) {
1792:                    Exceptions.printStackTrace(ioe);
1793:                }
1794:
1795:                return result[0];
1796:            }
1797:
1798:            /** Collect nodes of the given types (node.nodeId==NodeTypes.x) under the given root */
1799:            public static void addNodesByType(Node root, int[] nodeIds,
1800:                    List<Node> result) {
1801:                for (int i = 0; i < nodeIds.length; i++) {
1802:                    if (root.nodeId == nodeIds[i]) {
1803:                        result.add(root);
1804:                        break;
1805:                    }
1806:                }
1807:
1808:                @SuppressWarnings("unchecked")
1809:                List<Node> list = root.childNodes();
1810:
1811:                for (Node child : list) {
1812:                    addNodesByType(child, nodeIds, result);
1813:                }
1814:            }
1815:
1816:            /** Return all the blocknodes that apply to the given node. The outermost block
1817:             * is returned first.
1818:             */
1819:            public static List<Node> getApplicableBlocks(AstPath path,
1820:                    boolean includeNested) {
1821:                Node block = AstUtilities.findBlock(path);
1822:
1823:                if (block == null) {
1824:                    // Use parent
1825:                    block = path.leafParent();
1826:
1827:                    if (block == null) {
1828:                        return Collections.emptyList();
1829:                    }
1830:                }
1831:
1832:                List<Node> result = new ArrayList<Node>();
1833:                Iterator<Node> it = path.leafToRoot();
1834:
1835:                // Skip the leaf node, we're going to add it unconditionally afterwards
1836:                if (includeNested) {
1837:                    if (it.hasNext()) {
1838:                        it.next();
1839:                    }
1840:                }
1841:
1842:                Node leaf = path.root();
1843:
1844:                while_loop: while (it.hasNext()) {
1845:                    Node n = it.next();
1846:                    switch (n.nodeId) {
1847:                    //case NodeTypes.BLOCKNODE:
1848:                    case NodeTypes.ITERNODE:
1849:                        leaf = n;
1850:                        result.add(n);
1851:                        break;
1852:                    case NodeTypes.DEFNNODE:
1853:                    case NodeTypes.DEFSNODE:
1854:                    case NodeTypes.CLASSNODE:
1855:                    case NodeTypes.SCLASSNODE:
1856:                    case NodeTypes.MODULENODE:
1857:                        leaf = n;
1858:                        break while_loop;
1859:                    }
1860:                }
1861:
1862:                if (includeNested) {
1863:                    addNodesByType(
1864:                            leaf,
1865:                            new int[] { /*NodeTypes.BLOCKNODE,*/NodeTypes.ITERNODE },
1866:                            result);
1867:                }
1868:
1869:                return result;
1870:            }
1871:
1872:            public static String guessName(CompilationInfo info,
1873:                    OffsetRange lexRange, OffsetRange astRange) {
1874:                String guessedName = "";
1875:
1876:                // Try to guess the name - see if it's in a method and if so name it after the parameter
1877:                IndexedMethod[] methodHolder = new IndexedMethod[1];
1878:                @SuppressWarnings("unchecked")
1879:                Set<IndexedMethod>[] alternatesHolder = new Set[1];
1880:                int[] paramIndexHolder = new int[1];
1881:                int[] anchorOffsetHolder = new int[1];
1882:                if (!CodeCompleter.computeMethodCall(info, lexRange.getStart(),
1883:                        astRange.getStart(), methodHolder, paramIndexHolder,
1884:                        anchorOffsetHolder, alternatesHolder)) {
1885:
1886:                    return guessedName;
1887:                }
1888:
1889:                IndexedMethod targetMethod = methodHolder[0];
1890:                int index = paramIndexHolder[0];
1891:
1892:                List<String> params = targetMethod.getParameters();
1893:                if (params == null || params.size() <= index) {
1894:                    return guessedName;
1895:                }
1896:
1897:                return params.get(index);
1898:            }
1899:
1900:            public static Set<String> getUsedFields(RubyIndex index,
1901:                    AstPath path) {
1902:                String fqn = AstUtilities.getFqnName(path);
1903:                if (fqn == null || fqn.length() == 0) {
1904:                    return Collections.emptySet();
1905:                }
1906:                Set<IndexedField> fields = index.getInheritedFields(fqn, "",
1907:                        NameKind.PREFIX, false);
1908:                Set<String> fieldNames = new HashSet<String>();
1909:                for (IndexedField f : fields) {
1910:                    fieldNames.add(f.getName());
1911:                }
1912:
1913:                return fieldNames;
1914:            }
1915:
1916:            public static Set<String> getUsedMethods(RubyIndex index,
1917:                    AstPath path) {
1918:                String fqn = AstUtilities.getFqnName(path);
1919:                if (fqn == null || fqn.length() == 0) {
1920:                    return Collections.emptySet();
1921:                }
1922:                Set<IndexedMethod> methods = index.getInheritedMethods(fqn, "",
1923:                        NameKind.PREFIX);
1924:                Set<String> methodNames = new HashSet<String>();
1925:                for (IndexedMethod m : methods) {
1926:                    methodNames.add(m.getName());
1927:                }
1928:
1929:                return methodNames;
1930:            }
1931:
1932:            /** @todo Implement properly */
1933:            public static Set<String> getUsedConstants(RubyIndex index,
1934:                    AstPath path) {
1935:                //String fqn = AstUtilities.getFqnName(path);
1936:                //if (fqn == null || fqn.length() == 0) {
1937:                return Collections.emptySet();
1938:                //}
1939:                //Set<IndexedConstant> constants = index.getInheritedConstants(fqn, "", NameKind.PREFIX);
1940:                //Set<String> constantNames = new HashSet<String>();
1941:                //for (IndexedConstant m : constants) {
1942:                //    constantNames.add(m.getName());
1943:                //}
1944:                //
1945:                //return constantNames;
1946:            }
1947:
1948:            public static Set<String> getUsedLocalNames(AstPath path,
1949:                    Node closest) {
1950:                Node method = AstUtilities.findLocalScope(closest, path);
1951:                Map<String, Node> variables = new HashMap<String, Node>();
1952:                // Add locals
1953:                CodeCompleter.addLocals(method, variables);
1954:
1955:                List<Node> applicableBlocks = AstUtilities.getApplicableBlocks(
1956:                        path, false);
1957:                for (Node block : applicableBlocks) {
1958:                    CodeCompleter.addDynamic(block, variables);
1959:                }
1960:
1961:                return variables.keySet();
1962:            }
1963:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.