/** * Main loop entry. * * <p>First, it delegates to the super visitClass so we can collect the relevant annotations in an * AST tree walk. * * <p>Second, it calls the visit method on the transformation for each relevant annotation found. * * @param classNode the class to visit */ public void visitClass(ClassNode classNode) { // only descend if we have annotations to look for Map<Class<? extends ASTTransformation>, Set<ASTNode>> baseTransforms = classNode.getTransforms(phase); if (!baseTransforms.isEmpty()) { final Map<Class<? extends ASTTransformation>, ASTTransformation> transformInstances = new HashMap<Class<? extends ASTTransformation>, ASTTransformation>(); for (Class<? extends ASTTransformation> transformClass : baseTransforms.keySet()) { try { transformInstances.put(transformClass, transformClass.newInstance()); } catch (InstantiationException e) { source .getErrorCollector() .addError( new SimpleMessage( "Could not instantiate Transformation Processor " + transformClass, // + " declared by " + // annotation.getClassNode().getName(), source)); } catch (IllegalAccessException e) { source .getErrorCollector() .addError( new SimpleMessage( "Could not instantiate Transformation Processor " + transformClass, // + " declared by " + // annotation.getClassNode().getName(), source)); } } // invert the map, is now one to many transforms = new HashMap<ASTNode, List<ASTTransformation>>(); for (Map.Entry<Class<? extends ASTTransformation>, Set<ASTNode>> entry : baseTransforms.entrySet()) { for (ASTNode node : entry.getValue()) { List<ASTTransformation> list = transforms.get(node); if (list == null) { list = new ArrayList<ASTTransformation>(); transforms.put(node, list); } list.add(transformInstances.get(entry.getKey())); } } targetNodes = new LinkedList<ASTNode[]>(); // first pass, collect nodes super.visitClass(classNode); // second pass, call visit on all of the collected nodes for (ASTNode[] node : targetNodes) { for (ASTTransformation snt : transforms.get(node[0])) { if (snt instanceof CompilationUnitAware) { ((CompilationUnitAware) snt).setCompilationUnit(context.getCompilationUnit()); } snt.visit(node, source); } } } }
public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { optimizer.visitClass( classNode, source); // GROOVY-4272: repositioned it here from staticImport if (!classNode.isSynthetic()) { GenericsVisitor genericsVisitor = new GenericsVisitor(source); genericsVisitor.visitClass(classNode); } // // Run the Verifier on the outer class // try { verifier.visitClass(classNode); } catch (GroovyRuntimeException rpe) { ASTNode node = rpe.getNode(); getErrorCollector() .addError( new SyntaxException( rpe.getMessage(), node.getLineNumber(), node.getColumnNumber(), node.getLastLineNumber(), node.getLastColumnNumber()), source); } LabelVerifier lv = new LabelVerifier(source); lv.visitClass(classNode); ClassCompletionVerifier completionVerifier = new ClassCompletionVerifier(source); completionVerifier.visitClass(classNode); ExtendedVerifier xverifier = new ExtendedVerifier(source); xverifier.visitClass(classNode); // because the class may be generated even if a error was found // and that class may have an invalid format we fail here if needed getErrorCollector().failIfErrors(); // // Prep the generator machinery // ClassVisitor visitor = createClassVisitor(); String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName()); // only show the file name and its extension like javac does in its stacktraces rather // than the full path // also takes care of both \ and / depending on the host compiling environment if (sourceName != null) sourceName = sourceName.substring( Math.max(sourceName.lastIndexOf('\\'), sourceName.lastIndexOf('/')) + 1); AsmClassGenerator generator = new AsmClassGenerator(source, context, visitor, sourceName); // // Run the generation and create the class (if required) // // GRECLIPSE: if there are errors, don't generate code. // code gen can fail unexpectedly if there was an earlier error. if (!source.getErrorCollector().hasErrors()) { // end generator.visitClass(classNode); byte[] bytes = ((ClassWriter) visitor).toByteArray(); /// GRECLIPSE: start: added classNode, sourceUnit /*old{ generatedClasses.add(new GroovyClass(classNode.getName(), bytes)); }*/ // newcode generatedClasses.add(new GroovyClass(classNode.getName(), bytes, classNode, source)); // end // // Handle any callback that's been set // if (CompilationUnit.this.classgenCallback != null) { classgenCallback.call(visitor, classNode); } // // Recurse for inner classes // LinkedList innerClasses = generator.getInnerClasses(); while (!innerClasses.isEmpty()) { classgen.call(source, context, (ClassNode) innerClasses.removeFirst()); } // GRECLIPSE: if there are errors, don't generate code } // end }