private List<FieldNode> getAnnotatedFieldOfClass(ClassNode target, ClassNode annotation) { List<FieldNode> result = new ArrayList<FieldNode>(); for (FieldNode fieldNode : target.getFields()) if (!fieldNode.getAnnotations(annotation).isEmpty()) result.add(fieldNode); return result; }
/** * Adds the annotation to the internal target list if a match is found. * * @param node the node to be processed */ public void visitAnnotations(AnnotatedNode node) { super.visitAnnotations(node); for (AnnotationNode annotation : node.getAnnotations()) { if (transforms.containsKey(annotation)) { targetNodes.add(new ASTNode[] {annotation, node}); } } }
/** * This method is used to add "bridge" methods for private methods of an inner/outer class, so * that the outer class is capable of calling them. It does basically the same job as access$000 * like methods in Java. * * @param node an inner/outer class node for which to generate bridge methods */ @SuppressWarnings("unchecked") private void addPrivateBridgeMethods(final ClassNode node) { Set<ASTNode> accessedMethods = (Set<ASTNode>) node.getNodeMetaData(StaticTypesMarker.PV_METHODS_ACCESS); if (accessedMethods == null) return; List<MethodNode> methods = new ArrayList<MethodNode>(node.getAllDeclaredMethods()); Map<MethodNode, MethodNode> privateBridgeMethods = (Map<MethodNode, MethodNode>) node.getNodeMetaData(PRIVATE_BRIDGE_METHODS); if (privateBridgeMethods != null) { // private bridge methods already added return; } privateBridgeMethods = new HashMap<MethodNode, MethodNode>(); int i = -1; final int access = Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC; for (MethodNode method : methods) { if (accessedMethods.contains(method)) { i++; Parameter[] methodParameters = method.getParameters(); Parameter[] newParams = new Parameter[methodParameters.length + 1]; System.arraycopy(methodParameters, 0, newParams, 1, methodParameters.length); newParams[0] = new Parameter(node.getPlainNodeReference(), "$that"); Expression arguments; if (method.getParameters() == null || method.getParameters().length == 0) { arguments = ArgumentListExpression.EMPTY_ARGUMENTS; } else { List<Expression> args = new LinkedList<Expression>(); for (Parameter parameter : methodParameters) { args.add(new VariableExpression(parameter)); } arguments = new ArgumentListExpression(args); } Expression receiver = method.isStatic() ? new ClassExpression(node) : new VariableExpression(newParams[0]); MethodCallExpression mce = new MethodCallExpression(receiver, method.getName(), arguments); mce.setMethodTarget(method); ExpressionStatement returnStatement = new ExpressionStatement(mce); MethodNode bridge = node.addMethod( "access$" + i, access, method.getReturnType(), newParams, method.getExceptions(), returnStatement); privateBridgeMethods.put(method, bridge); bridge.addAnnotation(new AnnotationNode(COMPILESTATIC_CLASSNODE)); } } if (!privateBridgeMethods.isEmpty()) { node.setNodeMetaData(PRIVATE_BRIDGE_METHODS, privateBridgeMethods); } }
private List<ClassNode> getSorted(int[] index, List<ClassNode> unsorted) { List<ClassNode> sorted = new ArrayList<ClassNode>(unsorted.size()); for (int i = 0; i < unsorted.size(); i++) { int min = -1; for (int j = 0; j < unsorted.size(); j++) { if (index[j] == -1) continue; if (min == -1) { min = j; } else if (index[j] < index[min]) { min = j; } } if (min == -1) break; sorted.add(unsorted.get(min)); index[min] = -1; } return sorted; }
private Collection createPropertiesForBelongsToExpression(Expression e, ClassNode classNode) { List properties = new ArrayList(); if (e instanceof MapExpression) { MapExpression me = (MapExpression) e; List mapEntries = me.getMapEntryExpressions(); for (Iterator i = mapEntries.iterator(); i.hasNext(); ) { MapEntryExpression mme = (MapEntryExpression) i.next(); String key = mme.getKeyExpression().getText(); String type = mme.getValueExpression().getText(); properties.add( new PropertyNode( key, Modifier.PUBLIC, ClassHelper.make(type), classNode, null, null, null)); } } return properties; }
/** * Dequeues any source units add through addSource and resets the compiler phase to * initialization. * * <p>Note: this does not mean a file is recompiled. If a SourceUnit has already passed a phase it * is skipped until a higher phase is reached. * * @return true if there was a queued source * @throws CompilationFailedException */ protected boolean dequeued() throws CompilationFailedException { boolean dequeue = !queuedSources.isEmpty(); while (!queuedSources.isEmpty()) { SourceUnit su = queuedSources.removeFirst(); String name = su.getName(); // GRECLIPSE: start if (iterating) { GroovyBugError gbe = new GroovyBugError( "Damaging 'names' whilst already iterating. Name getting added is '" + su.getName() + "'"); gbe.printStackTrace(); throw gbe; } // end names.add(name); sources.put(name, su); } if (dequeue) { gotoPhase(Phases.INITIALIZATION); } return dequeue; }
/** * 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 }
private List getPrimaryClassNodes(boolean sort) { if (sort == true) { List<ModuleNode> sortedModules = this.ast.getSortedModules(); if (sortedModules != null) { return sortedModules; } } // FIXASC (groovychange) rewritten /*old{ List unsorted = new ArrayList(); Iterator modules = this.ast.getModules().iterator(); while (modules.hasNext()) { ModuleNode module = (ModuleNode) modules.next(); Iterator classNodes = module.getClasses().iterator(); while (classNodes.hasNext()) { ClassNode classNode = (ClassNode) classNodes.next(); unsorted.add(classNode); } } */ // new List<ClassNode> unsorted = new ArrayList<ClassNode>(); for (ModuleNode module : this.ast.getModules()) { unsorted.addAll(module.getClasses()); } // FIXASC (groovychange) end if (!sort) return unsorted; // GRECLIPSE: start: rewritten sort algorithm /*old{ int[] indexClass = new int[unsorted.size()]; int[] indexInterface = new int[unsorted.size()]; { int i = 0; for (Iterator<ClassNode> iter = unsorted.iterator(); iter.hasNext(); i++) { ClassNode element = iter.next(); if (element.isInterface()) { indexInterface[i] = getSuperInterfaceCount(element); indexClass[i] = -1; } else { indexClass[i] = getSuperClassCount(element); indexInterface[i] = -1; } } } List<ClassNode> sorted = getSorted(indexInterface, unsorted); sorted.addAll(getSorted(indexClass, unsorted)); */ // newcode: // Sort them by how many types are in their hierarchy, but all interfaces first. // Algorithm: // Create a list of integers. Each integer captures the index into the unsorted // list (bottom 16bits) and the count of how many types are in that types // hierarchy (top 16bits). For classes the count is augmented by 2000 so that // when sorting the classes will come out after the interfaces. // This list of integers is sorted. We then just go through it and for the // lower 16bits of each entry (0xffff) that is the index of the next value to // pull from the unsorted list and put into the sorted list. // Will break down if more than 2000 interfaces in the type hierarchy for an // individual type, or a project contains > 65535 files... but if you've got // that kind of setup, you have other problems... List<Integer> countIndexPairs = new ArrayList<Integer>(); { int i = 0; for (Iterator iter = unsorted.iterator(); iter.hasNext(); i++) { ClassNode node = (ClassNode) iter.next(); if (node.isInterface()) { countIndexPairs.add((getSuperInterfaceCount(node) << 16) + i); } else { countIndexPairs.add(((getSuperClassCount(node) + 2000) << 16) + i); } } } Collections.sort(countIndexPairs); List sorted = new ArrayList(); for (int i : countIndexPairs) { sorted.add(unsorted.get(i & 0xffff)); } this.ast.setSortedModules(sorted); // end return sorted; }
private void addAssociationForKey(String key, List properties, ClassNode classNode) { properties.add( new PropertyNode( key, Modifier.PUBLIC, new ClassNode(Set.class), classNode, null, null, null)); }