resolvevisitor.java
来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 853 行 · 第 1/3 页
JAVA
853 行
// Special handling for file:// protocol, as getLastModified() often reports
// incorrect results (-1)
if (source.getProtocol().equals("file")) {
// Coerce the file URL to a File
String path = source.getPath().replace('/', File.separatorChar).replace('|', ':');
File file = new File(path);
lastMod = file.lastModified();
}
else {
lastMod = source.openConnection().getLastModified();
}
return lastMod > getTimeStamp(cls);
} catch (IOException e) {
// if the stream can't be opened, let's keep the old reference
return false;
}
}
private boolean resolveToScript(ClassNode type) {
String name = type.getName();
if (cachedClasses.get(name)==NO_CLASS) return false;
if (cachedClasses.get(name)==SCRIPT) cachedClasses.put(name,NO_CLASS);
if (name.startsWith("java.")) return type.isResolved();
//TODO: don't ignore inner static classes completly
if (name.indexOf('$')!=-1) return type.isResolved();
ModuleNode module = currentClass.getModule();
if (module.hasPackageName() && name.indexOf('.')==-1) return type.isResolved();
// try to find a script from classpath
GroovyClassLoader gcl = compilationUnit.getClassLoader();
URL url = null;
try {
url = gcl.getResourceLoader().loadGroovySource(name);
} catch (MalformedURLException e) {
// fall through and let the URL be null
}
if (url !=null) {
if (type.isResolved()) {
Class cls = type.getTypeClass();
// if the file is not newer we don't want to recompile
if (!isSourceNewer(url,cls)) return true;
cachedClasses.remove(type.getName());
type.setRedirect(null);
}
SourceUnit su = compilationUnit.addSource(url);
currentClass.getCompileUnit().addClassNodeToCompile(type,su);
return true;
}
// type may be resolved through the classloader before
return type.isResolved();
}
private boolean resolveFromStaticInnerClasses(ClassNode type, boolean testStaticInnerClasses) {
// try to resolve a public static inner class' name
testStaticInnerClasses &= type.hasPackageName();
if (testStaticInnerClasses) {
String name = type.getName();
String replacedPointType = name;
int lastPoint = replacedPointType.lastIndexOf('.');
replacedPointType = new StringBuffer()
.append(replacedPointType.substring(0, lastPoint))
.append("$")
.append(replacedPointType.substring(lastPoint + 1))
.toString();
type.setName(replacedPointType);
if (resolve(type,false,false,true)) return true;
type.setName(name);
}
return false;
}
private boolean resovleFromDefaultImports(ClassNode type, boolean testDefaultImports) {
// test default imports
testDefaultImports &= !type.hasPackageName();
if (testDefaultImports) {
for (int i = 0, size = DEFAULT_IMPORTS.length; i < size; i++) {
String packagePrefix = DEFAULT_IMPORTS[i];
String name = type.getName();
String fqn = packagePrefix+name;
type.setName(fqn);
if (resolve(type,false,false,false)) return true;
type.setName(name);
}
String name = type.getName();
if (name.equals("BigInteger")) {
type.setRedirect(ClassHelper.BigInteger_TYPE);
return true;
} else if (name.equals("BigDecimal")) {
type.setRedirect(ClassHelper.BigDecimal_TYPE);
return true;
}
}
return false;
}
private boolean resolveFromCompileUnit(ClassNode type) {
// look into the compile unit if there is a class with that name
CompileUnit compileUnit = currentClass.getCompileUnit();
if (compileUnit == null) return false;
ClassNode cuClass = compileUnit.getClass(type.getName());
if (cuClass!=null) {
if (type!=cuClass) type.setRedirect(cuClass);
return true;
}
return false;
}
private void setClass(ClassNode n, Class cls) {
ClassNode cn = ClassHelper.make(cls);
n.setRedirect(cn);
}
private void ambigousClass(ClassNode type, ClassNode iType, String name, boolean resolved){
if (resolved && !type.getName().equals(iType.getName())) {
addError("reference to "+name+" is ambigous, both class "+type.getName()+" and "+iType.getName()+" match",type);
} else {
type.setRedirect(iType);
}
}
private boolean resolveAliasFromModule(ClassNode type) {
ModuleNode module = currentClass.getModule();
if (module==null) return false;
String name = type.getName();
// check module node imports aliases
// the while loop enables a check for inner classes which are not fully imported,
// but visible as the surrounding class is imported and the inner class is public/protected static
String pname = name;
int index = name.length();
/*
* we have a name foo.bar and an import foo.foo. This means foo.bar is possibly
* foo.foo.bar rather than foo.bar. This means to cut at the dot in foo.bar and
* foo for import
*/
while (true) {
pname = name.substring(0,index);
ClassNode aliasedNode = module.getImport(pname);
if (aliasedNode!=null) {
if (pname.length()==name.length()){
// full match, no need to create a new class
type.setRedirect(aliasedNode);
return true;
} else {
//partial match
String newName = aliasedNode.getName()+name.substring(pname.length());
type.setName(newName);
if (resolve(type,true,true,true)) return true;
// was not resolved soit was a fake match
type.setName(name);
}
}
index = pname.lastIndexOf('.');
if (index==-1) break;
}
return false;
}
private boolean resolveFromModule(ClassNode type, boolean testModuleImports) {
ModuleNode module = currentClass.getModule();
if (module==null) return false;
String name = type.getName();
if (!type.hasPackageName() && module.hasPackageName()){
type.setName(module.getPackageName()+name);
}
// look into the module node if there is a class with that name
List moduleClasses = module.getClasses();
for (Iterator iter = moduleClasses.iterator(); iter.hasNext();) {
ClassNode mClass = (ClassNode) iter.next();
if (mClass.getName().equals(type.getName())){
if (mClass!=type) type.setRedirect(mClass);
return true;
}
}
type.setName(name);
if (testModuleImports) {
if (resolveAliasFromModule(type)) return true;
boolean resolved = false;
if (module.hasPackageName()) {
// check package this class is defined in
type.setName(module.getPackageName()+name);
resolved = resolve(type,false,false,false);
}
// check module node imports packages
List packages = module.getImportPackages();
ClassNode iType = ClassHelper.makeWithoutCaching(name);
for (Iterator iter = packages.iterator(); iter.hasNext();) {
String packagePrefix = (String) iter.next();
String fqn = packagePrefix+name;
iType.setName(fqn);
if (resolve(iType,false,false,true)) {
ambigousClass(type,iType,name,resolved);
return true;
}
iType.setName(name);
}
if (!resolved) type.setName(name);
return resolved;
}
return false;
}
private boolean resolveToClass(ClassNode type) {
String name = type.getName();
if (cachedClasses.get(name)==NO_CLASS) return false;
if (currentClass.getModule().hasPackageName() && name.indexOf('.')==-1) return false;
GroovyClassLoader loader = compilationUnit.getClassLoader();
Class cls = null;
try {
// NOTE: it's important to do no lookup against script files
// here since the GroovyClassLoader would create a new
// CompilationUnit
cls = loader.loadClass(name,false,true);
} catch (ClassNotFoundException cnfe) {
cachedClasses.put(name,SCRIPT);
return false;
} catch (CompilationFailedException cfe) {
compilationUnit.getErrorCollector().addErrorAndContinue(new ExceptionMessage(cfe,true,source));
return false;
}
//TODO: the case of a NoClassDefFoundError needs a bit more research
// a simple recompilation is not possible it seems. The current class
// we are searching for is there, so we should mark that somehow.
// Basically the missing class needs to be completly compiled before
// we can again search for the current name.
/*catch (NoClassDefFoundError ncdfe) {
cachedClasses.put(name,SCRIPT);
return false;
}*/
if (cls==null) return false;
cachedClasses.put(name,cls);
setClass(type,cls);
//NOTE: we return false here even if we found a class,
//but we want to give a possible script a chance to recompile.
//this can only be done if the loader was not the instance
//defining the class.
return cls.getClassLoader()==loader;
}
public Expression transform(Expression exp) {
if (exp==null) return null;
if (exp instanceof VariableExpression) {
return transformVariableExpression((VariableExpression) exp);
} else if (exp.getClass()==PropertyExpression.class) {
return transformPropertyExpression((PropertyExpression) exp);
} else if (exp instanceof DeclarationExpression) {
return transformDeclarationExpression((DeclarationExpression)exp);
} else if (exp instanceof BinaryExpression) {
return transformBinaryExpression((BinaryExpression)exp);
} else if (exp instanceof MethodCallExpression) {
return transformMethodCallExpression((MethodCallExpression)exp);
} else if (exp instanceof ClosureExpression) {
return transformClosureExpression((ClosureExpression) exp);
} else if (exp instanceof ConstructorCallExpression) {
return transformConstructorCallExpression((ConstructorCallExpression) exp);
} else {
resolveOrFail(exp.getType(),exp);
return exp.transformExpression(this);
}
}
private String lookupClassName(PropertyExpression pe) {
String name = "";
for (Expression it = pe; it!=null; it = ((PropertyExpression)it).getObjectExpression()) {
if (it instanceof VariableExpression) {
VariableExpression ve = (VariableExpression) it;
// stop at super and this
if (ve==VariableExpression.SUPER_EXPRESSION || ve==VariableExpression.THIS_EXPRESSION) {
return null;
}
name= ve.getName()+"."+name;
break;
}
// anything other than PropertyExpressions, ClassExpression or
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?