📄 resolvevisitor.java
字号:
// NOTE: copied from GroovyClassLoader private boolean isSourceNewer(URL source, Class cls) { try { long lastMod; // 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); } compilationUnit.addSource(url); currentClass.getCompileUnit().addClassNodeToCompile(type,url.toString()); 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 instanceof PropertyExpression) { 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); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -