public void visit()

in src/main/java/groovy/grape/GrabAnnotationTransformation.java [166:389]


    public void visit(final ASTNode[] nodes, final SourceUnit source) {
        loader = null;
        sourceUnit = source;
        initContextClassLoader = false;
        allowShortGrab         = true;
        allowShortGrabExcludes = true;
        allowShortGrabConfig   = true;
        allowShortGrapes       = true;
        allowShortGrabResolver = true;
        grabAliases         = new HashSet<>();
        grabExcludeAliases  = new HashSet<>();
        grabConfigAliases   = new HashSet<>();
        grapesAliases       = new HashSet<>();
        grabResolverAliases = new HashSet<>();
        ModuleNode mn = (ModuleNode) nodes[0];
        for (ImportNode im : mn.getImports()) {
            String alias     = im.getAlias();
            String className = im.getClassName();
            boolean hasAlias = (alias != null && !alias.isBlank());
            if ((className.endsWith(GRAB_DOT_NAME) && !hasAlias) || GRAB_CLASS_NAME.equals(alias)) {
                allowShortGrab = false;
            } else if (GRAB_CLASS_NAME.equals(className)) {
                grabAliases.add(im.getAlias());
            }
            if ((className.endsWith(GRAPES_DOT_NAME) && !hasAlias) || GRAPES_CLASS_NAME.equals(alias)) {
                allowShortGrapes = false;
            } else if (GRAPES_CLASS_NAME.equals(className)) {
                grapesAliases.add(im.getAlias());
            }
            if ((className.endsWith(GRABRESOLVER_DOT_NAME) && !hasAlias) || GRABRESOLVER_CLASS_NAME.equals(alias)) {
                allowShortGrabResolver = false;
            } else if (GRABRESOLVER_CLASS_NAME.equals(className)) {
                grabResolverAliases.add(im.getAlias());
            }
        }
        ClassNode grapeClassNode = ClassHelper.make(Grape.class);
        Collection<Map<String,Object>> grabMaps = new LinkedHashSet<>();
        Collection<Map<String,Object>> grabMapsInit = new ArrayList<>();
        Collection<Map<String,Object>> grabExcludeMaps = new ArrayList<>();

        for (ClassNode classNode : sourceUnit.getAST().getClasses()) {
            grabAnnotations         = new ArrayList<>();
            grabExcludeAnnotations  = new ArrayList<>();
            grabConfigAnnotations   = new ArrayList<>();
            grapesAnnotations       = new ArrayList<>();
            grabResolverAnnotations = new ArrayList<>();

            if (classNode.getOuterClass() == null) {
                visitClass(classNode);
            } else { // GROOVY-11409
                visitAnnotations(classNode);
                classNode.visitContents(this);
            }

            List<Statement> grabResolverInitializers = new ArrayList<>();

            if (!grapesAnnotations.isEmpty()) {
                for (AnnotationNode node : grapesAnnotations) {
                    Expression init = node.getMember("initClass");
                    Expression value = node.getMember("value");
                    if (value instanceof ListExpression) {
                        for (Expression e : ((ListExpression) value).getExpressions()) {
                            if (e instanceof ConstantExpression) {
                                extractGrab(init, (ConstantExpression) e);
                            }
                        }
                    } else if (value instanceof ConstantExpression) {
                        extractGrab(init, (ConstantExpression) value);
                    }
                    // don't worry if it's not a ListExpression, or AnnotationConstant, etc.
                    // the rest of GroovyC will flag it as a syntax error later, so we don't
                    // need to raise the error ourselves
                }
            }

            if (!grabResolverAnnotations.isEmpty()) {
                grabResolverAnnotationLoop:
                for (AnnotationNode node : grabResolverAnnotations) {
                    Map<String, Object> grabResolverMap = new HashMap<String, Object>();
                    String sval = getMemberStringValue(node, "value");
                    if (sval != null && sval.length() > 0) {
                        for (String s : GRABRESOLVER_REQUIRED) {
                            String mval = getMemberStringValue(node, s);
                            if (mval != null && mval.isEmpty()) mval = null;
                            if (mval != null) {
                                addError("The attribute \"" + s + "\" conflicts with attribute 'value' in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                                continue grabResolverAnnotationLoop;
                            }
                        }
                        grabResolverMap.put("name", sval);
                        grabResolverMap.put("root", sval);
                    } else {
                        for (String s : GRABRESOLVER_REQUIRED) {
                            String mval = getMemberStringValue(node, s);
                            Expression member = node.getMember(s);
                            if (member == null || (mval != null && mval.isEmpty())) {
                                addError("The missing attribute \"" + s + "\" is required in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                                continue grabResolverAnnotationLoop;
                            } else if (mval == null) {
                                addError("Attribute \"" + s + "\" has value " + member.getText() + " but should be an inline constant String in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                                continue grabResolverAnnotationLoop;
                            }
                            grabResolverMap.put(s, mval);
                        }
                    }

                    // If no scheme is specified for the repository root,
                    // then turn it into a URI relative to that of the source file.
                    String root = (String) grabResolverMap.get("root");
                    if (root != null && !root.contains(":")) {
                        URI sourceURI = null;
                        // Since we use the data: scheme for StringReaderSources (which are fairly common)
                        // and those are not hierarchical we can't use them for making an absolute URI.
                        if (!(getSourceUnit().getSource() instanceof StringReaderSource)) {
                            // Otherwise let's trust the source to know where it is from.
                            // And actually InputStreamReaderSource doesn't know what to do and so returns null.
                            sourceURI = getSourceUnit().getSource().getURI();
                        }
                        // If source doesn't know how to get a reference to itself,
                        // then let's use the current working directory, since the repo can be relative to that.
                        if (sourceURI == null) {
                            sourceURI = new File(".").toURI();
                        }
                        try {
                            URI rootURI = sourceURI.resolve(new URI(root));
                            grabResolverMap.put("root", rootURI.toString());
                        } catch (URISyntaxException e) {
                            // We'll be silent here.
                            // If the URI scheme is unknown or not hierarchical, then we just can't help them and shouldn't cause any trouble either.
                            // addError("Attribute \"root\" has value '" + root + "' which can't be turned into a valid URI relative to its source '" + getSourceUnit().getName() + "' @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                        }
                    }

                    Grape.addResolver(grabResolverMap);
                    addGrabResolverAsStaticInitIfNeeded(grapeClassNode, node, grabResolverInitializers, grabResolverMap);
                }
            }

            if (!grabConfigAnnotations.isEmpty()) {
                for (AnnotationNode node : grabConfigAnnotations) {
                    checkForClassLoader(node);
                    checkForInitContextClassLoader(node);
                    checkForAutoDownload(node);
                    checkForSystemProperties(node);
                    checkForDisableChecksums(node);
                }
                addInitContextClassLoaderIfNeeded(classNode);
            }

            if (!grabExcludeAnnotations.isEmpty()) {
                grabExcludeAnnotationLoop:
                for (AnnotationNode node : grabExcludeAnnotations) {
                    Map<String, Object> grabExcludeMap = new HashMap<>();
                    checkForConvenienceForm(node, true);
                    for (String s : GRABEXCLUDE_REQUIRED) {
                        Expression member = node.getMember(s);
                        if (member == null) {
                            addError("The missing attribute \"" + s + "\" is required in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                            continue grabExcludeAnnotationLoop;
                        } else if (!(member instanceof ConstantExpression)) {
                            addError("Attribute \"" + s + "\" has value " + member.getText() + " but should be an inline constant in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                            continue grabExcludeAnnotationLoop;
                        }
                        grabExcludeMap.put(s, ((ConstantExpression)member).getValue());
                    }
                    grabExcludeMaps.add(grabExcludeMap);
                }
            }

            if (!grabAnnotations.isEmpty()) {
                grabAnnotationLoop:
                for (AnnotationNode node : grabAnnotations) {
                    Map<String, Object> grabMap = new HashMap<>();
                    checkForConvenienceForm(node, false);
                    for (String s : GRAB_ALL) {
                        Expression member = node.getMember(s);
                        String mval = getMemberStringValue(node, s);
                        if (mval != null && mval.isEmpty()) member = null;
                        if (member == null && !GRAB_OPTIONAL.contains(s)) {
                            addError("The missing attribute \"" + s + "\" is required in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                            continue grabAnnotationLoop;
                        } else if (member != null && !(member instanceof ConstantExpression)) {
                            addError("Attribute \"" + s + "\" has value " + member.getText() + " but should be an inline constant in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                            continue grabAnnotationLoop;
                        }
                        if (node.getMember(s) != null) {
                            grabMap.put(s, ((ConstantExpression)member).getValue());
                        }
                    }
                    grabMaps.add(grabMap);
                    if ((node.getMember("initClass") == null) || (node.getMember("initClass") == ConstantExpression.TRUE)) {
                        grabMapsInit.add(grabMap);
                    }
                }
                callGrabAsStaticInitIfNeeded(classNode, grapeClassNode, grabMapsInit, grabExcludeMaps);
            }

            if (!grabResolverInitializers.isEmpty()) {
                classNode.addStaticInitializerStatements(grabResolverInitializers, true);
            }
        }

        if (!grabMaps.isEmpty()) {
            Map<String, Object> basicArgs = new HashMap<>();
            basicArgs.put("classLoader", loader != null ? loader : sourceUnit.getClassLoader());
            if (!grabExcludeMaps.isEmpty()) basicArgs.put("excludes", grabExcludeMaps);
            if (autoDownload != null) basicArgs.put(AUTO_DOWNLOAD_SETTING, autoDownload);
            if (disableChecksums != null) basicArgs.put(DISABLE_CHECKSUMS_SETTING, disableChecksums);
            if (systemProperties != null) basicArgs.put(SYSTEM_PROPERTIES_SETTING, systemProperties);

            try {
                Grape.grab(basicArgs, grabMaps.toArray(Map[]::new));
                // grab may have added more transformations through new URLs added to classpath, so do one more scan
                if (compilationUnit != null) {
                    ASTTransformationVisitor.addGlobalTransformsAfterGrab(compilationUnit.getASTTransformationsContext());
                }
            } catch (RuntimeException re) {
                // Decided against syntax exception since this is not a syntax error.
                // The downside is we lose line number information for the offending
                // @Grab annotation.
                source.addException(re);
            }
        }
    }