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 + -
显示快捷键?