resolvevisitor.java
来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 853 行 · 第 1/3 页
JAVA
853 行
/*
* $Id: ResolveVisitor.java 4295 2006-12-02 21:15:54Z blackdrag $
*
* Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
*
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided that the
* following conditions are met: 1. Redistributions of source code must retain
* copyright statements and notices. Redistributions must also contain a copy
* of this document. 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution. 3.
* The name "groovy" must not be used to endorse or promote products derived
* from this Software without prior written permission of The Codehaus. For
* written permission, please contact info@codehaus.org. 4. Products derived
* from this Software may not be called "groovy" nor may "groovy" appear in
* their names without prior written permission of The Codehaus. "groovy" is a
* registered trademark of The Codehaus. 5. Due credit should be given to The
* Codehaus - http://groovy.codehaus.org/
*
* THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*/
package org.codehaus.groovy.control;
import groovy.lang.GroovyClassLoader;
import java.io.IOException;
import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.net.URL;
import java.net.MalformedURLException;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.CompileUnit;
import org.codehaus.groovy.ast.ConstructorNode;
import org.codehaus.groovy.ast.DynamicVariable;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.ImportNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.ModuleNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.PropertyNode;
import org.codehaus.groovy.ast.Variable;
import org.codehaus.groovy.ast.VariableScope;
import org.codehaus.groovy.ast.expr.BinaryExpression;
import org.codehaus.groovy.ast.expr.BooleanExpression;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ClosureExpression;
import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
import org.codehaus.groovy.ast.expr.DeclarationExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.ExpressionTransformer;
import org.codehaus.groovy.ast.expr.ListExpression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.AssertStatement;
import org.codehaus.groovy.ast.stmt.BlockStatement;
import org.codehaus.groovy.ast.stmt.CaseStatement;
import org.codehaus.groovy.ast.stmt.CatchStatement;
import org.codehaus.groovy.ast.stmt.DoWhileStatement;
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
import org.codehaus.groovy.ast.stmt.ForStatement;
import org.codehaus.groovy.ast.stmt.IfStatement;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.ast.stmt.SwitchStatement;
import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
import org.codehaus.groovy.ast.stmt.ThrowStatement;
import org.codehaus.groovy.ast.stmt.WhileStatement;
import org.codehaus.groovy.classgen.Verifier;
import org.codehaus.groovy.control.messages.ExceptionMessage;
import org.codehaus.groovy.syntax.Types;
/**
* Visitor to resolve Types and convert VariableExpression to
* ClassExpressions if needed. The ResolveVisitor will try to
* find the Class for a ClassExpression and prints an error if
* it fails to do so. Constructions like C[], foo as C, (C) foo
* will force creation of a ClasssExpression for C
*
* Note: the method to start the resolving is startResolving(ClassNode, SourceUnit).
*
*
* @author Jochen Theodorou
*/
public class ResolveVisitor extends ClassCodeVisitorSupport implements ExpressionTransformer {
private ClassNode currentClass;
// note: BigInteger and BigDecimal are also imported by default
private static final String[] DEFAULT_IMPORTS = {"java.lang.", "java.io.", "java.net.", "java.util.", "groovy.lang.", "groovy.util."};
private CompilationUnit compilationUnit;
private Map cachedClasses = new HashMap();
private static final Object NO_CLASS = new Object();
private static final Object SCRIPT = new Object();
private SourceUnit source;
private VariableScope currentScope;
private boolean isTopLevelProperty = true;
private boolean inClosure = false;
public ResolveVisitor(CompilationUnit cu) {
compilationUnit = cu;
}
public void startResolving(ClassNode node,SourceUnit source) {
this.source = source;
visitClass(node);
}
public void visitConstructor(ConstructorNode node) {
visitAnnotations(node);
VariableScope oldScope = currentScope;
currentScope = node.getVariableScope();
Parameter[] paras = node.getParameters();
for (int i=0; i<paras.length; i++) {
ClassNode t = paras[i].getType();
resolveOrFail(t,node);
}
ClassNode[] exceptions = node.getExceptions();
for (int i=0; i<exceptions.length; i++) {
ClassNode t = exceptions[i];
resolveOrFail(t,node);
}
Statement code = node.getCode();
if (code!=null) code.visit(this);
currentScope = oldScope;
}
public void visitSwitch(SwitchStatement statement) {
Expression exp = statement.getExpression();
statement.setExpression(transform(exp));
List list = statement.getCaseStatements();
for (Iterator iter = list.iterator(); iter.hasNext(); ) {
CaseStatement caseStatement = (CaseStatement) iter.next();
caseStatement.visit(this);
}
statement.getDefaultStatement().visit(this);
}
public void visitMethod(MethodNode node) {
visitAnnotations(node);
VariableScope oldScope = currentScope;
currentScope = node.getVariableScope();
Parameter[] paras = node.getParameters();
for (int i=0; i<paras.length; i++) {
ClassNode t = paras[i].getType();
resolveOrFail(t,node);
if (paras[i].hasInitialExpression()) {
Expression init = paras[i].getInitialExpression();
paras[i].setInitialExpression(transform(init));
}
}
ClassNode[] exceptions = node.getExceptions();
for (int i=0; i<exceptions.length; i++) {
ClassNode t = exceptions[i];
resolveOrFail(t,node);
}
resolveOrFail(node.getReturnType(),node);
Statement code = node.getCode();
if (code!=null) code.visit(this);
currentScope = oldScope;
}
public void visitField(FieldNode node) {
visitAnnotations(node);
ClassNode t = node.getType();
resolveOrFail(t,node);
Expression init = node.getInitialExpression();
node.setInitialValueExpression(transform(init));
}
public void visitProperty(PropertyNode node) {
visitAnnotations(node);
ClassNode t = node.getType();
resolveOrFail(t,node);
Statement code = node.getGetterBlock();
if (code!=null) code.visit(this);
code = node.getSetterBlock();
if (code!=null) code.visit(this);
}
public void visitIfElse(IfStatement ifElse) {
visitStatement(ifElse);
ifElse.setBooleanExpression((BooleanExpression) (transform(ifElse.getBooleanExpression())));
ifElse.getIfBlock().visit(this);
ifElse.getElseBlock().visit(this);
}
private void resolveOrFail(ClassNode type, String msg, ASTNode node) {
if (resolve(type)) return;
addError("unable to resolve class "+type.getName()+" "+msg,node);
}
private void resolveOrFail(ClassNode type, ASTNode node, boolean prefereImports) {
if (prefereImports && resolveAliasFromModule(type)) return;
resolveOrFail(type,node);
}
private void resolveOrFail(ClassNode type, ASTNode node) {
resolveOrFail(type,"",node);
}
private boolean resolve(ClassNode type) {
String name = type.getName();
return resolve(type,true,true,true);
}
private boolean resolve(ClassNode type, boolean testModuleImports, boolean testDefaultImports, boolean testStaticInnerClasses) {
if (type.isResolved()) return true;
if (type.isArray()) {
ClassNode element = type.getComponentType();
boolean resolved = resolve(element,testModuleImports,testDefaultImports,testStaticInnerClasses);
if (resolved) {
ClassNode cn = element.makeArray();
type.setRedirect(cn);
}
return resolved;
}
// test if vanilla name is current class name
if (currentClass==type) return true;
if (currentClass.getNameWithoutPackage().equals(type.getName())) {
type.setRedirect(currentClass);
return true;
}
return resolveFromModule(type,testModuleImports) ||
resolveFromCompileUnit(type) ||
resovleFromDefaultImports(type,testDefaultImports) ||
resolveFromStaticInnerClasses(type,testStaticInnerClasses) ||
resolveFromClassCache(type) ||
resolveToClass(type) ||
resolveToScript(type);
}
private boolean resolveFromClassCache(ClassNode type) {
String name = type.getName();
Object val = cachedClasses.get(name);
if (val==null || val==NO_CLASS){
return false;
} else {
setClass(type,(Class) val);
return true;
}
}
// NOTE: copied from GroovyClassLoader
private long getTimeStamp(Class cls) {
Field field;
Long o;
try {
field = cls.getField(Verifier.__TIMESTAMP);
o = (Long) field.get(null);
} catch (Exception e) {
return Long.MAX_VALUE;
}
return o.longValue();
}
// NOTE: copied from GroovyClassLoader
private boolean isSourceNewer(URL source, Class cls) {
try {
long lastMod;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?