Source Code Cross Referenced for ResolveVisitor.java in  » Scripting » groovy-1.0 » org » codehaus » groovy » control » 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 » Scripting » groovy 1.0 » org.codehaus.groovy.control 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: ResolveVisitor.java 4295 2006-12-02 21:15:54Z blackdrag $
003:         *
004:         * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005:         *
006:         * Redistribution and use of this software and associated documentation
007:         * ("Software"), with or without modification, are permitted provided that the
008:         * following conditions are met: 1. Redistributions of source code must retain
009:         * copyright statements and notices. Redistributions must also contain a copy
010:         * of this document. 2. Redistributions in binary form must reproduce the above
011:         * copyright notice, this list of conditions and the following disclaimer in
012:         * the documentation and/or other materials provided with the distribution. 3.
013:         * The name "groovy" must not be used to endorse or promote products derived
014:         * from this Software without prior written permission of The Codehaus. For
015:         * written permission, please contact info@codehaus.org. 4. Products derived
016:         * from this Software may not be called "groovy" nor may "groovy" appear in
017:         * their names without prior written permission of The Codehaus. "groovy" is a
018:         * registered trademark of The Codehaus. 5. Due credit should be given to The
019:         * Codehaus - http://groovy.codehaus.org/
020:         *
021:         * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
022:         * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
023:         * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
024:         * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
025:         * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
026:         * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
027:         * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
028:         * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
029:         * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
030:         * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
031:         * DAMAGE.
032:         *
033:         */
034:        package org.codehaus.groovy.control;
035:
036:        import groovy.lang.GroovyClassLoader;
037:
038:        import java.io.IOException;
039:        import java.io.File;
040:        import java.lang.reflect.Field;
041:        import java.util.HashMap;
042:        import java.util.Iterator;
043:        import java.util.LinkedList;
044:        import java.util.List;
045:        import java.util.Map;
046:        import java.net.URL;
047:        import java.net.MalformedURLException;
048:
049:        import org.codehaus.groovy.ast.ASTNode;
050:        import org.codehaus.groovy.ast.AnnotatedNode;
051:        import org.codehaus.groovy.ast.AnnotationNode;
052:        import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
053:        import org.codehaus.groovy.ast.ClassHelper;
054:        import org.codehaus.groovy.ast.ClassNode;
055:        import org.codehaus.groovy.ast.CompileUnit;
056:        import org.codehaus.groovy.ast.ConstructorNode;
057:        import org.codehaus.groovy.ast.DynamicVariable;
058:        import org.codehaus.groovy.ast.FieldNode;
059:        import org.codehaus.groovy.ast.ImportNode;
060:        import org.codehaus.groovy.ast.MethodNode;
061:        import org.codehaus.groovy.ast.ModuleNode;
062:        import org.codehaus.groovy.ast.Parameter;
063:        import org.codehaus.groovy.ast.PropertyNode;
064:        import org.codehaus.groovy.ast.Variable;
065:        import org.codehaus.groovy.ast.VariableScope;
066:        import org.codehaus.groovy.ast.expr.BinaryExpression;
067:        import org.codehaus.groovy.ast.expr.BooleanExpression;
068:        import org.codehaus.groovy.ast.expr.ClassExpression;
069:        import org.codehaus.groovy.ast.expr.ClosureExpression;
070:        import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
071:        import org.codehaus.groovy.ast.expr.DeclarationExpression;
072:        import org.codehaus.groovy.ast.expr.Expression;
073:        import org.codehaus.groovy.ast.expr.ExpressionTransformer;
074:        import org.codehaus.groovy.ast.expr.ListExpression;
075:        import org.codehaus.groovy.ast.expr.MethodCallExpression;
076:        import org.codehaus.groovy.ast.expr.PropertyExpression;
077:        import org.codehaus.groovy.ast.expr.VariableExpression;
078:        import org.codehaus.groovy.ast.stmt.AssertStatement;
079:        import org.codehaus.groovy.ast.stmt.BlockStatement;
080:        import org.codehaus.groovy.ast.stmt.CaseStatement;
081:        import org.codehaus.groovy.ast.stmt.CatchStatement;
082:        import org.codehaus.groovy.ast.stmt.DoWhileStatement;
083:        import org.codehaus.groovy.ast.stmt.ExpressionStatement;
084:        import org.codehaus.groovy.ast.stmt.ForStatement;
085:        import org.codehaus.groovy.ast.stmt.IfStatement;
086:        import org.codehaus.groovy.ast.stmt.ReturnStatement;
087:        import org.codehaus.groovy.ast.stmt.Statement;
088:        import org.codehaus.groovy.ast.stmt.SwitchStatement;
089:        import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
090:        import org.codehaus.groovy.ast.stmt.ThrowStatement;
091:        import org.codehaus.groovy.ast.stmt.WhileStatement;
092:        import org.codehaus.groovy.classgen.Verifier;
093:        import org.codehaus.groovy.control.messages.ExceptionMessage;
094:        import org.codehaus.groovy.syntax.Types;
095:
096:        /**
097:         * Visitor to resolve Types and convert VariableExpression to
098:         * ClassExpressions if needed. The ResolveVisitor will try to
099:         * find the Class for a ClassExpression and prints an error if
100:         * it fails to do so. Constructions like C[], foo as C, (C) foo 
101:         * will force creation of a ClasssExpression for C   
102:         *
103:         * Note: the method to start the resolving is  startResolving(ClassNode, SourceUnit).
104:         *
105:         *
106:         * @author Jochen Theodorou
107:         */
108:        public class ResolveVisitor extends ClassCodeVisitorSupport implements 
109:                ExpressionTransformer {
110:            private ClassNode currentClass;
111:            // note: BigInteger and BigDecimal are also imported by default
112:            private static final String[] DEFAULT_IMPORTS = { "java.lang.",
113:                    "java.io.", "java.net.", "java.util.", "groovy.lang.",
114:                    "groovy.util." };
115:            private CompilationUnit compilationUnit;
116:            private Map cachedClasses = new HashMap();
117:            private static final Object NO_CLASS = new Object();
118:            private static final Object SCRIPT = new Object();
119:            private SourceUnit source;
120:            private VariableScope currentScope;
121:
122:            private boolean isTopLevelProperty = true;
123:            private boolean inClosure = false;
124:
125:            public ResolveVisitor(CompilationUnit cu) {
126:                compilationUnit = cu;
127:            }
128:
129:            public void startResolving(ClassNode node, SourceUnit source) {
130:                this .source = source;
131:                visitClass(node);
132:            }
133:
134:            public void visitConstructor(ConstructorNode node) {
135:                visitAnnotations(node);
136:                VariableScope oldScope = currentScope;
137:                currentScope = node.getVariableScope();
138:                Parameter[] paras = node.getParameters();
139:                for (int i = 0; i < paras.length; i++) {
140:                    ClassNode t = paras[i].getType();
141:                    resolveOrFail(t, node);
142:                }
143:                ClassNode[] exceptions = node.getExceptions();
144:                for (int i = 0; i < exceptions.length; i++) {
145:                    ClassNode t = exceptions[i];
146:                    resolveOrFail(t, node);
147:                }
148:                Statement code = node.getCode();
149:                if (code != null)
150:                    code.visit(this );
151:                currentScope = oldScope;
152:            }
153:
154:            public void visitSwitch(SwitchStatement statement) {
155:                Expression exp = statement.getExpression();
156:                statement.setExpression(transform(exp));
157:                List list = statement.getCaseStatements();
158:                for (Iterator iter = list.iterator(); iter.hasNext();) {
159:                    CaseStatement caseStatement = (CaseStatement) iter.next();
160:                    caseStatement.visit(this );
161:                }
162:                statement.getDefaultStatement().visit(this );
163:            }
164:
165:            public void visitMethod(MethodNode node) {
166:                visitAnnotations(node);
167:                VariableScope oldScope = currentScope;
168:                currentScope = node.getVariableScope();
169:                Parameter[] paras = node.getParameters();
170:                for (int i = 0; i < paras.length; i++) {
171:                    ClassNode t = paras[i].getType();
172:                    resolveOrFail(t, node);
173:                    if (paras[i].hasInitialExpression()) {
174:                        Expression init = paras[i].getInitialExpression();
175:                        paras[i].setInitialExpression(transform(init));
176:                    }
177:                }
178:                ClassNode[] exceptions = node.getExceptions();
179:                for (int i = 0; i < exceptions.length; i++) {
180:                    ClassNode t = exceptions[i];
181:                    resolveOrFail(t, node);
182:                }
183:                resolveOrFail(node.getReturnType(), node);
184:                Statement code = node.getCode();
185:                if (code != null)
186:                    code.visit(this );
187:                currentScope = oldScope;
188:            }
189:
190:            public void visitField(FieldNode node) {
191:                visitAnnotations(node);
192:                ClassNode t = node.getType();
193:                resolveOrFail(t, node);
194:                Expression init = node.getInitialExpression();
195:                node.setInitialValueExpression(transform(init));
196:            }
197:
198:            public void visitProperty(PropertyNode node) {
199:                visitAnnotations(node);
200:                ClassNode t = node.getType();
201:                resolveOrFail(t, node);
202:                Statement code = node.getGetterBlock();
203:                if (code != null)
204:                    code.visit(this );
205:                code = node.getSetterBlock();
206:                if (code != null)
207:                    code.visit(this );
208:            }
209:
210:            public void visitIfElse(IfStatement ifElse) {
211:                visitStatement(ifElse);
212:                ifElse
213:                        .setBooleanExpression((BooleanExpression) (transform(ifElse
214:                                .getBooleanExpression())));
215:                ifElse.getIfBlock().visit(this );
216:                ifElse.getElseBlock().visit(this );
217:            }
218:
219:            private void resolveOrFail(ClassNode type, String msg, ASTNode node) {
220:                if (resolve(type))
221:                    return;
222:                addError("unable to resolve class " + type.getName() + " "
223:                        + msg, node);
224:            }
225:
226:            private void resolveOrFail(ClassNode type, ASTNode node,
227:                    boolean prefereImports) {
228:                if (prefereImports && resolveAliasFromModule(type))
229:                    return;
230:                resolveOrFail(type, node);
231:            }
232:
233:            private void resolveOrFail(ClassNode type, ASTNode node) {
234:                resolveOrFail(type, "", node);
235:            }
236:
237:            private boolean resolve(ClassNode type) {
238:                String name = type.getName();
239:                return resolve(type, true, true, true);
240:            }
241:
242:            private boolean resolve(ClassNode type, boolean testModuleImports,
243:                    boolean testDefaultImports, boolean testStaticInnerClasses) {
244:                if (type.isResolved())
245:                    return true;
246:                if (type.isArray()) {
247:                    ClassNode element = type.getComponentType();
248:                    boolean resolved = resolve(element, testModuleImports,
249:                            testDefaultImports, testStaticInnerClasses);
250:                    if (resolved) {
251:                        ClassNode cn = element.makeArray();
252:                        type.setRedirect(cn);
253:                    }
254:                    return resolved;
255:                }
256:
257:                // test if vanilla name is current class name
258:                if (currentClass == type)
259:                    return true;
260:                if (currentClass.getNameWithoutPackage().equals(type.getName())) {
261:                    type.setRedirect(currentClass);
262:                    return true;
263:                }
264:
265:                return resolveFromModule(type, testModuleImports)
266:                        || resolveFromCompileUnit(type)
267:                        || resovleFromDefaultImports(type, testDefaultImports)
268:                        || resolveFromStaticInnerClasses(type,
269:                                testStaticInnerClasses)
270:                        || resolveFromClassCache(type) || resolveToClass(type)
271:                        || resolveToScript(type);
272:
273:            }
274:
275:            private boolean resolveFromClassCache(ClassNode type) {
276:                String name = type.getName();
277:                Object val = cachedClasses.get(name);
278:                if (val == null || val == NO_CLASS) {
279:                    return false;
280:                } else {
281:                    setClass(type, (Class) val);
282:                    return true;
283:                }
284:            }
285:
286:            // NOTE: copied from GroovyClassLoader
287:            private long getTimeStamp(Class cls) {
288:                Field field;
289:                Long o;
290:                try {
291:                    field = cls.getField(Verifier.__TIMESTAMP);
292:                    o = (Long) field.get(null);
293:                } catch (Exception e) {
294:                    return Long.MAX_VALUE;
295:                }
296:                return o.longValue();
297:            }
298:
299:            // NOTE: copied from GroovyClassLoader
300:            private boolean isSourceNewer(URL source, Class cls) {
301:                try {
302:                    long lastMod;
303:
304:                    // Special handling for file:// protocol, as getLastModified() often reports
305:                    // incorrect results (-1)
306:                    if (source.getProtocol().equals("file")) {
307:                        // Coerce the file URL to a File
308:                        String path = source.getPath().replace('/',
309:                                File.separatorChar).replace('|', ':');
310:                        File file = new File(path);
311:                        lastMod = file.lastModified();
312:                    } else {
313:                        lastMod = source.openConnection().getLastModified();
314:                    }
315:                    return lastMod > getTimeStamp(cls);
316:                } catch (IOException e) {
317:                    // if the stream can't be opened, let's keep the old reference
318:                    return false;
319:                }
320:            }
321:
322:            private boolean resolveToScript(ClassNode type) {
323:                String name = type.getName();
324:                if (cachedClasses.get(name) == NO_CLASS)
325:                    return false;
326:                if (cachedClasses.get(name) == SCRIPT)
327:                    cachedClasses.put(name, NO_CLASS);
328:                if (name.startsWith("java."))
329:                    return type.isResolved();
330:                //TODO: don't ignore inner static classes completly
331:                if (name.indexOf('$') != -1)
332:                    return type.isResolved();
333:                ModuleNode module = currentClass.getModule();
334:                if (module.hasPackageName() && name.indexOf('.') == -1)
335:                    return type.isResolved();
336:                // try to find a script from classpath
337:                GroovyClassLoader gcl = compilationUnit.getClassLoader();
338:                URL url = null;
339:                try {
340:                    url = gcl.getResourceLoader().loadGroovySource(name);
341:                } catch (MalformedURLException e) {
342:                    // fall through and let the URL be null
343:                }
344:                if (url != null) {
345:                    if (type.isResolved()) {
346:                        Class cls = type.getTypeClass();
347:                        // if the file is not newer we don't want to recompile
348:                        if (!isSourceNewer(url, cls))
349:                            return true;
350:                        cachedClasses.remove(type.getName());
351:                        type.setRedirect(null);
352:                    }
353:                    SourceUnit su = compilationUnit.addSource(url);
354:                    currentClass.getCompileUnit().addClassNodeToCompile(type,
355:                            su);
356:                    return true;
357:                }
358:                // type may be resolved through the classloader before
359:                return type.isResolved();
360:            }
361:
362:            private boolean resolveFromStaticInnerClasses(ClassNode type,
363:                    boolean testStaticInnerClasses) {
364:                // try to resolve a public static inner class' name
365:                testStaticInnerClasses &= type.hasPackageName();
366:                if (testStaticInnerClasses) {
367:                    String name = type.getName();
368:                    String replacedPointType = name;
369:                    int lastPoint = replacedPointType.lastIndexOf('.');
370:                    replacedPointType = new StringBuffer().append(
371:                            replacedPointType.substring(0, lastPoint)).append(
372:                            "$").append(
373:                            replacedPointType.substring(lastPoint + 1))
374:                            .toString();
375:                    type.setName(replacedPointType);
376:                    if (resolve(type, false, false, true))
377:                        return true;
378:                    type.setName(name);
379:                }
380:                return false;
381:            }
382:
383:            private boolean resovleFromDefaultImports(ClassNode type,
384:                    boolean testDefaultImports) {
385:                // test default imports
386:                testDefaultImports &= !type.hasPackageName();
387:                if (testDefaultImports) {
388:                    for (int i = 0, size = DEFAULT_IMPORTS.length; i < size; i++) {
389:                        String packagePrefix = DEFAULT_IMPORTS[i];
390:                        String name = type.getName();
391:                        String fqn = packagePrefix + name;
392:                        type.setName(fqn);
393:                        if (resolve(type, false, false, false))
394:                            return true;
395:                        type.setName(name);
396:                    }
397:                    String name = type.getName();
398:                    if (name.equals("BigInteger")) {
399:                        type.setRedirect(ClassHelper.BigInteger_TYPE);
400:                        return true;
401:                    } else if (name.equals("BigDecimal")) {
402:                        type.setRedirect(ClassHelper.BigDecimal_TYPE);
403:                        return true;
404:                    }
405:                }
406:                return false;
407:            }
408:
409:            private boolean resolveFromCompileUnit(ClassNode type) {
410:                // look into the compile unit if there is a class with that name
411:                CompileUnit compileUnit = currentClass.getCompileUnit();
412:                if (compileUnit == null)
413:                    return false;
414:                ClassNode cuClass = compileUnit.getClass(type.getName());
415:                if (cuClass != null) {
416:                    if (type != cuClass)
417:                        type.setRedirect(cuClass);
418:                    return true;
419:                }
420:                return false;
421:            }
422:
423:            private void setClass(ClassNode n, Class cls) {
424:                ClassNode cn = ClassHelper.make(cls);
425:                n.setRedirect(cn);
426:            }
427:
428:            private void ambigousClass(ClassNode type, ClassNode iType,
429:                    String name, boolean resolved) {
430:                if (resolved && !type.getName().equals(iType.getName())) {
431:                    addError("reference to " + name
432:                            + " is ambigous, both class " + type.getName()
433:                            + " and " + iType.getName() + " match", type);
434:                } else {
435:                    type.setRedirect(iType);
436:                }
437:            }
438:
439:            private boolean resolveAliasFromModule(ClassNode type) {
440:                ModuleNode module = currentClass.getModule();
441:                if (module == null)
442:                    return false;
443:                String name = type.getName();
444:
445:                // check module node imports aliases
446:                // the while loop enables a check for inner classes which are not fully imported,
447:                // but visible as the surrounding class is imported and the inner class is public/protected static
448:                String pname = name;
449:                int index = name.length();
450:                /*
451:                 * we have a name foo.bar and an import foo.foo. This means foo.bar is possibly
452:                 * foo.foo.bar rather than foo.bar. This means to cut at the dot in foo.bar and
453:                 * foo for import
454:                 */
455:                while (true) {
456:                    pname = name.substring(0, index);
457:                    ClassNode aliasedNode = module.getImport(pname);
458:                    if (aliasedNode != null) {
459:                        if (pname.length() == name.length()) {
460:                            // full match, no need to create a new class
461:                            type.setRedirect(aliasedNode);
462:                            return true;
463:                        } else {
464:                            //partial match
465:                            String newName = aliasedNode.getName()
466:                                    + name.substring(pname.length());
467:                            type.setName(newName);
468:                            if (resolve(type, true, true, true))
469:                                return true;
470:                            // was not resolved soit was a fake match
471:                            type.setName(name);
472:                        }
473:                    }
474:                    index = pname.lastIndexOf('.');
475:                    if (index == -1)
476:                        break;
477:                }
478:                return false;
479:
480:            }
481:
482:            private boolean resolveFromModule(ClassNode type,
483:                    boolean testModuleImports) {
484:                ModuleNode module = currentClass.getModule();
485:                if (module == null)
486:                    return false;
487:
488:                String name = type.getName();
489:
490:                if (!type.hasPackageName() && module.hasPackageName()) {
491:                    type.setName(module.getPackageName() + name);
492:                }
493:                // look into the module node if there is a class with that name
494:                List moduleClasses = module.getClasses();
495:                for (Iterator iter = moduleClasses.iterator(); iter.hasNext();) {
496:                    ClassNode mClass = (ClassNode) iter.next();
497:                    if (mClass.getName().equals(type.getName())) {
498:                        if (mClass != type)
499:                            type.setRedirect(mClass);
500:                        return true;
501:                    }
502:                }
503:                type.setName(name);
504:
505:                if (testModuleImports) {
506:                    if (resolveAliasFromModule(type))
507:                        return true;
508:
509:                    boolean resolved = false;
510:                    if (module.hasPackageName()) {
511:                        // check package this class is defined in
512:                        type.setName(module.getPackageName() + name);
513:                        resolved = resolve(type, false, false, false);
514:                    }
515:                    // check module node imports packages
516:                    List packages = module.getImportPackages();
517:                    ClassNode iType = ClassHelper.makeWithoutCaching(name);
518:                    for (Iterator iter = packages.iterator(); iter.hasNext();) {
519:                        String packagePrefix = (String) iter.next();
520:                        String fqn = packagePrefix + name;
521:                        iType.setName(fqn);
522:                        if (resolve(iType, false, false, true)) {
523:                            ambigousClass(type, iType, name, resolved);
524:                            return true;
525:                        }
526:                        iType.setName(name);
527:                    }
528:                    if (!resolved)
529:                        type.setName(name);
530:                    return resolved;
531:                }
532:                return false;
533:            }
534:
535:            private boolean resolveToClass(ClassNode type) {
536:                String name = type.getName();
537:                if (cachedClasses.get(name) == NO_CLASS)
538:                    return false;
539:                if (currentClass.getModule().hasPackageName()
540:                        && name.indexOf('.') == -1)
541:                    return false;
542:                GroovyClassLoader loader = compilationUnit.getClassLoader();
543:                Class cls = null;
544:                try {
545:                    // NOTE: it's important to do no lookup against script files
546:                    // here since the GroovyClassLoader would create a new
547:                    // CompilationUnit
548:                    cls = loader.loadClass(name, false, true);
549:                } catch (ClassNotFoundException cnfe) {
550:                    cachedClasses.put(name, SCRIPT);
551:                    return false;
552:                } catch (CompilationFailedException cfe) {
553:                    compilationUnit.getErrorCollector().addErrorAndContinue(
554:                            new ExceptionMessage(cfe, true, source));
555:                    return false;
556:                }
557:                //TODO: the case of a NoClassDefFoundError needs a bit more research
558:                // a simple recompilation is not possible it seems. The current class
559:                // we are searching for is there, so we should mark that somehow. 
560:                // Basically the missing class needs to be completly compiled before
561:                // we can again search for the current name.
562:                /*catch (NoClassDefFoundError ncdfe) {
563:                    cachedClasses.put(name,SCRIPT);
564:                    return false;
565:                }*/
566:                if (cls == null)
567:                    return false;
568:                cachedClasses.put(name, cls);
569:                setClass(type, cls);
570:                //NOTE: we return false here even if we found a class,
571:                //but we want to give a possible script a chance to recompile.
572:                //this can only be done if the loader was not the instance
573:                //defining the class.
574:                return cls.getClassLoader() == loader;
575:            }
576:
577:            public Expression transform(Expression exp) {
578:                if (exp == null)
579:                    return null;
580:                if (exp instanceof  VariableExpression) {
581:                    return transformVariableExpression((VariableExpression) exp);
582:                } else if (exp.getClass() == PropertyExpression.class) {
583:                    return transformPropertyExpression((PropertyExpression) exp);
584:                } else if (exp instanceof  DeclarationExpression) {
585:                    return transformDeclarationExpression((DeclarationExpression) exp);
586:                } else if (exp instanceof  BinaryExpression) {
587:                    return transformBinaryExpression((BinaryExpression) exp);
588:                } else if (exp instanceof  MethodCallExpression) {
589:                    return transformMethodCallExpression((MethodCallExpression) exp);
590:                } else if (exp instanceof  ClosureExpression) {
591:                    return transformClosureExpression((ClosureExpression) exp);
592:                } else if (exp instanceof  ConstructorCallExpression) {
593:                    return transformConstructorCallExpression((ConstructorCallExpression) exp);
594:                } else {
595:                    resolveOrFail(exp.getType(), exp);
596:                    return exp.transformExpression(this );
597:                }
598:            }
599:
600:            private String lookupClassName(PropertyExpression pe) {
601:                String name = "";
602:                for (Expression it = pe; it != null; it = ((PropertyExpression) it)
603:                        .getObjectExpression()) {
604:                    if (it instanceof  VariableExpression) {
605:                        VariableExpression ve = (VariableExpression) it;
606:                        // stop at super and this
607:                        if (ve == VariableExpression.SUPER_EXPRESSION
608:                                || ve == VariableExpression.THIS_EXPRESSION) {
609:                            return null;
610:                        }
611:                        name = ve.getName() + "." + name;
612:                        break;
613:                    }
614:                    // anything other than PropertyExpressions, ClassExpression or
615:                    // VariableExpressions will stop resolving
616:                    else if (!(it.getClass() == PropertyExpression.class)) {
617:                        return null;
618:                    } else {
619:                        PropertyExpression current = (PropertyExpression) it;
620:                        String propertyPart = current.getPropertyAsString();
621:                        // the class property stops resolving, dynamic property names too
622:                        if (propertyPart == null
623:                                || propertyPart.equals("class")) {
624:                            return null;
625:                        }
626:                        name = propertyPart + "." + name;
627:                    }
628:                }
629:                if (name.length() > 0)
630:                    return name.substring(0, name.length() - 1);
631:                return null;
632:            }
633:
634:            // iterate from the inner most to the outer and check for classes
635:            // this check will ignore a .class property, for Exmaple Integer.class will be
636:            // a PropertyExpression with the ClassExpression of Integer as objectExpression
637:            // and class as property
638:            private Expression correctClassClassChain(PropertyExpression pe) {
639:                LinkedList stack = new LinkedList();
640:                ClassExpression found = null;
641:                for (Expression it = pe; it != null; it = ((PropertyExpression) it)
642:                        .getObjectExpression()) {
643:                    if (it instanceof  ClassExpression) {
644:                        found = (ClassExpression) it;
645:                        break;
646:                    } else if (!(it.getClass() == PropertyExpression.class)) {
647:                        return pe;
648:                    }
649:                    stack.addFirst(it);
650:                }
651:                if (found == null)
652:                    return pe;
653:
654:                if (stack.isEmpty())
655:                    return pe;
656:                Object stackElement = stack.removeFirst();
657:                if (!(stackElement.getClass() == PropertyExpression.class))
658:                    return pe;
659:                PropertyExpression classPropertyExpression = (PropertyExpression) stackElement;
660:                String propertyNamePart = classPropertyExpression
661:                        .getPropertyAsString();
662:                if (propertyNamePart == null
663:                        || !propertyNamePart.equals("class"))
664:                    return pe;
665:
666:                if (stack.isEmpty())
667:                    return found;
668:                stackElement = stack.removeFirst();
669:                if (!(stackElement.getClass() == PropertyExpression.class))
670:                    return pe;
671:                PropertyExpression classPropertyExpressionContainer = (PropertyExpression) stackElement;
672:
673:                classPropertyExpressionContainer.setObjectExpression(found);
674:                return pe;
675:            }
676:
677:            protected Expression transformPropertyExpression(
678:                    PropertyExpression pe) {
679:                boolean itlp = isTopLevelProperty;
680:
681:                Expression objectExpression = pe.getObjectExpression();
682:                isTopLevelProperty = !(objectExpression.getClass() == PropertyExpression.class);
683:                objectExpression = transform(objectExpression);
684:                Expression property = transform(pe.getProperty());
685:                isTopLevelProperty = itlp;
686:
687:                boolean spreadSafe = pe.isSpreadSafe();
688:                pe = new PropertyExpression(objectExpression, property, pe
689:                        .isSafe());
690:                pe.setSpreadSafe(spreadSafe);
691:
692:                String className = lookupClassName(pe);
693:                if (className != null) {
694:                    ClassNode type = ClassHelper.make(className);
695:                    if (resolve(type))
696:                        return new ClassExpression(type);
697:                }
698:                if (objectExpression instanceof  ClassExpression
699:                        && pe.getPropertyAsString() != null) {
700:                    // possibly a inner class
701:                    ClassExpression ce = (ClassExpression) objectExpression;
702:                    ClassNode type = ClassHelper.make(ce.getType().getName()
703:                            + "$" + pe.getPropertyAsString());
704:                    if (resolve(type, false, false, false))
705:                        return new ClassExpression(type);
706:                }
707:                if (isTopLevelProperty)
708:                    return correctClassClassChain(pe);
709:
710:                return pe;
711:            }
712:
713:            protected Expression transformVariableExpression(
714:                    VariableExpression ve) {
715:                if (ve.getName().equals("this"))
716:                    return VariableExpression.THIS_EXPRESSION;
717:                if (ve.getName().equals("super"))
718:                    return VariableExpression.SUPER_EXPRESSION;
719:                Variable v = ve.getAccessedVariable();
720:                if (v instanceof  DynamicVariable) {
721:                    ClassNode t = ClassHelper.make(ve.getName());
722:                    if (resolve(t)) {
723:                        // the name is a type so remove it from the scoping
724:                        // as it is only a classvariable, it is only in 
725:                        // referencedClassVariables, but must be removed
726:                        // for each parentscope too
727:                        for (VariableScope scope = currentScope; scope != null
728:                                && !scope.isRoot(); scope = scope.getParent()) {
729:                            if (scope.isRoot())
730:                                break;
731:                            if (scope.getReferencedClassVariables().remove(
732:                                    ve.getName()) == null)
733:                                break;
734:                        }
735:                        ClassExpression ce = new ClassExpression(t);
736:                        ce.setSourcePosition(ve);
737:                        return ce;
738:                    } else if (!inClosure && ve.isInStaticContext()) {
739:                        addError(
740:                                "the name "
741:                                        + v.getName()
742:                                        + " doesn't refer to a declared variable or class. The static"
743:                                        + " scope requires to declare variables before using them. If the variable should have"
744:                                        + " been a class check the spelling.",
745:                                ve);
746:                    }
747:                }
748:                resolveOrFail(ve.getType(), ve);
749:                return ve;
750:            }
751:
752:            protected Expression transformBinaryExpression(BinaryExpression be) {
753:                Expression left = transform(be.getLeftExpression());
754:                if (be.getOperation().getType() == Types.ASSIGNMENT_OPERATOR
755:                        && left instanceof  ClassExpression) {
756:                    ClassExpression ce = (ClassExpression) left;
757:                    addError("you tried to assign a value to "
758:                            + ce.getType().getName(), be.getLeftExpression());
759:                    return be;
760:                }
761:                if (left instanceof  ClassExpression
762:                        && be.getRightExpression() instanceof  ListExpression) {
763:                    // we have C[] if the list is empty -> should be an array then!
764:                    ListExpression list = (ListExpression) be
765:                            .getRightExpression();
766:                    ClassExpression ce = (ClassExpression) left;
767:                    if (list.getExpressions().isEmpty()) {
768:                        return new ClassExpression(left.getType().makeArray());
769:                    }
770:                }
771:                Expression right = transform(be.getRightExpression());
772:                Expression ret = new BinaryExpression(left, be.getOperation(),
773:                        right);
774:                ret.setSourcePosition(be);
775:                return ret;
776:            }
777:
778:            protected Expression transformClosureExpression(ClosureExpression ce) {
779:                boolean oldInClosure = inClosure;
780:                inClosure = true;
781:                Parameter[] paras = ce.getParameters();
782:                if (paras != null) {
783:                    for (int i = 0; i < paras.length; i++) {
784:                        ClassNode t = paras[i].getType();
785:                        resolveOrFail(t, ce);
786:                    }
787:                }
788:                Statement code = ce.getCode();
789:                if (code != null)
790:                    code.visit(this );
791:                ClosureExpression newCe = new ClosureExpression(paras, code);
792:                newCe.setVariableScope(ce.getVariableScope());
793:                newCe.setSourcePosition(ce);
794:                inClosure = oldInClosure;
795:                return newCe;
796:            }
797:
798:            protected Expression transformConstructorCallExpression(
799:                    ConstructorCallExpression cce) {
800:                ClassNode type = cce.getType();
801:                resolveOrFail(type, cce);
802:                Expression expr = cce.transformExpression(this );
803:                return expr;
804:            }
805:
806:            protected Expression transformMethodCallExpression(
807:                    MethodCallExpression mce) {
808:                Expression obj = mce.getObjectExpression();
809:                Expression newObject = transform(obj);
810:                Expression args = transform(mce.getArguments());
811:                Expression method = transform(mce.getMethod());
812:                MethodCallExpression ret = new MethodCallExpression(newObject,
813:                        method, args);
814:                ret.setSafe(mce.isSafe());
815:                ret.setImplicitThis(mce.isImplicitThis());
816:                ret.setSpreadSafe(mce.isSpreadSafe());
817:                ret.setSourcePosition(mce);
818:                return ret;
819:            }
820:
821:            protected Expression transformDeclarationExpression(
822:                    DeclarationExpression de) {
823:                Expression oldLeft = de.getLeftExpression();
824:                Expression left = transform(oldLeft);
825:                if (left != oldLeft) {
826:                    ClassExpression ce = (ClassExpression) left;
827:                    addError("you tried to assign a value to "
828:                            + ce.getType().getName(), oldLeft);
829:                    return de;
830:                }
831:                Expression right = transform(de.getRightExpression());
832:                if (right == de.getRightExpression())
833:                    return de;
834:                return new DeclarationExpression((VariableExpression) left, de
835:                        .getOperation(), right);
836:            }
837:
838:            public void visitAnnotations(AnnotatedNode node) {
839:                Map annotionMap = node.getAnnotations();
840:                if (annotionMap.isEmpty())
841:                    return;
842:                Iterator it = annotionMap.values().iterator();
843:                while (it.hasNext()) {
844:                    AnnotationNode an = (AnnotationNode) it.next();
845:                    //skip builtin properties
846:                    if (an.isBuiltIn())
847:                        continue;
848:                    ClassNode type = an.getClassNode();
849:                    resolveOrFail(type, "unable to find class for annotation",
850:                            an);
851:                }
852:            }
853:
854:            public void visitClass(ClassNode node) {
855:                ClassNode oldNode = currentClass;
856:                currentClass = node;
857:
858:                ModuleNode module = node.getModule();
859:                if (!module.hasImportsResolved()) {
860:                    List l = module.getImports();
861:                    for (Iterator iter = l.iterator(); iter.hasNext();) {
862:                        ImportNode element = (ImportNode) iter.next();
863:                        ClassNode type = element.getType();
864:                        if (resolve(type, false, false, false))
865:                            continue;
866:                        addError("unable to resolve class " + type.getName(),
867:                                type);
868:                    }
869:                    module.setImportsResolved(true);
870:                }
871:
872:                ClassNode sn = node.getUnresolvedSuperClass();
873:                if (sn != null)
874:                    resolveOrFail(sn, node, true);
875:                ClassNode[] interfaces = node.getInterfaces();
876:                for (int i = 0; i < interfaces.length; i++) {
877:                    resolveOrFail(interfaces[i], node, true);
878:                }
879:                super .visitClass(node);
880:                currentClass = oldNode;
881:            }
882:
883:            public void visitReturnStatement(ReturnStatement statement) {
884:                statement.setExpression(transform(statement.getExpression()));
885:            }
886:
887:            public void visitAssertStatement(AssertStatement as) {
888:                as.setBooleanExpression((BooleanExpression) (transform(as
889:                        .getBooleanExpression())));
890:                as.setMessageExpression(transform(as.getMessageExpression()));
891:            }
892:
893:            public void visitCaseStatement(CaseStatement statement) {
894:                statement.setExpression(transform(statement.getExpression()));
895:                statement.getCode().visit(this );
896:            }
897:
898:            public void visitCatchStatement(CatchStatement cs) {
899:                resolveOrFail(cs.getExceptionType(), cs);
900:                if (cs.getExceptionType() == ClassHelper.DYNAMIC_TYPE) {
901:                    cs.getVariable().setType(ClassHelper.make(Exception.class));
902:                }
903:                super .visitCatchStatement(cs);
904:            }
905:
906:            public void visitDoWhileLoop(DoWhileStatement loop) {
907:                loop.setBooleanExpression((BooleanExpression) (transform(loop
908:                        .getBooleanExpression())));
909:                super .visitDoWhileLoop(loop);
910:            }
911:
912:            public void visitForLoop(ForStatement forLoop) {
913:                forLoop.setCollectionExpression(transform(forLoop
914:                        .getCollectionExpression()));
915:                resolveOrFail(forLoop.getVariableType(), forLoop);
916:                super .visitForLoop(forLoop);
917:            }
918:
919:            public void visitSynchronizedStatement(SynchronizedStatement sync) {
920:                sync.setExpression(transform(sync.getExpression()));
921:                super .visitSynchronizedStatement(sync);
922:            }
923:
924:            public void visitThrowStatement(ThrowStatement ts) {
925:                ts.setExpression(transform(ts.getExpression()));
926:            }
927:
928:            public void visitWhileLoop(WhileStatement loop) {
929:                loop.setBooleanExpression((BooleanExpression) transform(loop
930:                        .getBooleanExpression()));
931:                super .visitWhileLoop(loop);
932:            }
933:
934:            public void visitExpressionStatement(ExpressionStatement es) {
935:                es.setExpression(transform(es.getExpression()));
936:            }
937:
938:            public void visitBlockStatement(BlockStatement block) {
939:                VariableScope oldScope = currentScope;
940:                currentScope = block.getVariableScope();
941:                super .visitBlockStatement(block);
942:                currentScope = oldScope;
943:            }
944:
945:            protected SourceUnit getSourceUnit() {
946:                return source;
947:            }
948:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.