/** * Main entry point for the calling the TestForTransformation programmatically. * * @param classNode The class node that represents th test * @param ce The class expression that represents the class to test */ public void testFor(ClassNode classNode, ClassExpression ce) { boolean junit3Test = isJunit3Test(classNode); // make sure the 'log' property is not the one from GroovyTestCase FieldNode log = classNode.getField("log"); if (log == null || log.getDeclaringClass().equals(GROOVY_TEST_CASE_CLASS)) { LoggingTransformer.addLogField(classNode, classNode.getName()); } boolean isSpockTest = isSpockTest(classNode); if (!isSpockTest && !junit3Test) { // assume JUnit 4 Map<String, MethodNode> declaredMethodsMap = classNode.getDeclaredMethodsMap(); for (String methodName : declaredMethodsMap.keySet()) { MethodNode methodNode = declaredMethodsMap.get(methodName); if (isCandidateMethod(methodNode) && methodNode.getName().startsWith("test")) { if (methodNode.getAnnotations().size() == 0) { methodNode.addAnnotation(TEST_ANNOTATION); } } } } final MethodNode methodToAdd = weaveMock(classNode, ce, true); if (methodToAdd != null && junit3Test) { addMethodCallsToMethod(classNode, SET_UP_METHOD, Arrays.asList(methodToAdd)); } }
private void createBuilderForAnnotatedMethod( BuilderASTTransformation transform, MethodNode mNode, AnnotationNode anno) { if (transform.getMemberValue(anno, "includes") != null || transform.getMemberValue(anno, "includes") != null) { transform.addError( "Error during " + BuilderASTTransformation.MY_TYPE_NAME + " processing: includes/excludes only allowed on classes", anno); } if (mNode instanceof ConstructorNode) { mNode.setModifiers(ACC_PRIVATE | ACC_SYNTHETIC); } else { if ((mNode.getModifiers() & ACC_STATIC) == 0) { transform.addError( "Error during " + BuilderASTTransformation.MY_TYPE_NAME + " processing: method builders only allowed on static methods", anno); } mNode.setModifiers(ACC_PRIVATE | ACC_SYNTHETIC | ACC_STATIC); } ClassNode buildee = mNode.getDeclaringClass(); Parameter[] parameters = mNode.getParameters(); ClassNode builder = createInnerHelperClass(buildee, getBuilderClassName(buildee, anno), parameters.length); List<FieldNode> convertedFields = convertParamsToFields(builder, parameters); buildCommon(buildee, anno, convertedFields, builder); if (mNode instanceof ConstructorNode) { createBuildeeConstructors(transform, buildee, builder, convertedFields, false); } else { createBuildeeMethods(buildee, mNode, builder, convertedFields); } }
@Override protected ClassNode createClosureClass(final ClosureExpression expression, final int mods) { ClassNode closureClass = super.createClosureClass(expression, mods); List<MethodNode> methods = closureClass.getDeclaredMethods("call"); List<MethodNode> doCall = closureClass.getMethods("doCall"); if (doCall.size() != 1) { throw new GroovyBugError( "Expected to find one (1) doCall method on generated closure, but found " + doCall.size()); } MethodNode doCallMethod = doCall.get(0); if (methods.isEmpty() && doCallMethod.getParameters().length == 1) { createDirectCallMethod(closureClass, doCallMethod); } MethodTargetCompletionVisitor visitor = new MethodTargetCompletionVisitor(doCallMethod); Object dynamic = expression.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION); if (dynamic != null) { doCallMethod.putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, dynamic); } for (MethodNode method : methods) { visitor.visitMethod(method); } closureClass.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.TRUE); return closureClass; }
public void visit(ASTNode[] nodes, SourceUnit source) { if (nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) { throw new RuntimeException( "Internal error: expecting [AnnotationNode, AnnotatedNode] but got: " + Arrays.asList(nodes)); } AnnotationNode annotationNode = (AnnotationNode) nodes[0]; ASTNode node = nodes[1]; if (!(node instanceof MethodNode)) { addError("@NotYetImplemented must only be applied on test methods!", node); return; } MethodNode methodNode = (MethodNode) node; ArrayList<Statement> statements = new ArrayList<Statement>(); Statement statement = methodNode.getCode(); if (statement instanceof BlockStatement) { statements.addAll(((BlockStatement) statement).getStatements()); } if (statements.size() == 0) return; BlockStatement rewrittenMethodCode = new BlockStatement(); rewrittenMethodCode.addStatement( tryCatchAssertionFailedError(annotationNode, methodNode, statements)); rewrittenMethodCode.addStatement(throwAssertionFailedError(annotationNode)); methodNode.setCode(rewrittenMethodCode); }
public static void addMethodIfNotPresent(ClassNode controllerClassNode, MethodNode methodNode) { MethodNode existing = controllerClassNode.getMethod(methodNode.getName(), methodNode.getParameters()); if (existing == null) { controllerClassNode.addMethod(methodNode); } }
public void visitConstructorCallExpression(ConstructorCallExpression call) { isSpecialConstructorCall = call.isSpecialCall(); super.visitConstructorCallExpression(call); isSpecialConstructorCall = false; if (!call.isUsingAnonymousInnerClass()) return; pushState(); InnerClassNode innerClass = (InnerClassNode) call.getType(); innerClass.setVariableScope(currentScope); for (MethodNode method : innerClass.getMethods()) { Parameter[] parameters = method.getParameters(); if (parameters.length == 0) parameters = null; // null means no implicit "it" ClosureExpression cl = new ClosureExpression(parameters, method.getCode()); visitClosureExpression(cl); } for (FieldNode field : innerClass.getFields()) { final Expression expression = field.getInitialExpression(); if (expression != null) { expression.visit(this); } } for (Statement statement : innerClass.getObjectInitializerStatements()) { statement.visit(this); } markClosureSharedVariables(); popState(); }
private void setMethodDefaultValue(MethodNode mn, Method m) { Object defaultValue = m.getDefaultValue(); ConstantExpression cExp = ConstantExpression.NULL; if (defaultValue != null) cExp = new ConstantExpression(defaultValue); mn.setCode(new ReturnStatement(cExp)); mn.setAnnotationDefault(true); }
/** * Adds the necessary field and methods to support resource locating. * * @param declaringClass the class to which we add the support field and methods */ public static void apply(@Nonnull ClassNode declaringClass, @Nullable String beanName) { injectInterface(declaringClass, EVENT_PUBLISHER_CNODE); FieldNode epField = injectField( declaringClass, EVENT_ROUTER_FIELD_NAME, PRIVATE, EVENT_PUBLISHER_FIELD_CNODE, null); Parameter erParam = param(EVENT_ROUTER_CNODE, EVENT_ROUTER_PROPERTY); if (!isBlank(beanName)) { AnnotationNode namedAnnotation = new AnnotationNode(NAMED_TYPE); namedAnnotation.addMember("value", new ConstantExpression(beanName)); erParam.addAnnotation(namedAnnotation); } MethodNode setter = new MethodNode( METHOD_SET_EVENT_ROUTER, PRIVATE, VOID_TYPE, params(erParam), NO_EXCEPTIONS, stmnt(call(field(epField), METHOD_SET_EVENT_ROUTER, args(var(EVENT_ROUTER_PROPERTY))))); setter.addAnnotation(new AnnotationNode(INJECT_TYPE)); injectMethod(declaringClass, setter); addDelegateMethods(declaringClass, EVENT_PUBLISHER_CNODE, field(epField)); }
private MethodNode toMethod(ClassNode declaringType, ResolverCache resolver) { if (cachedRegularParameters == null) { cachedRegularParameters = initParams(params, resolver); cachedOptionalParameters = initParams(optionalParams, resolver); cachedNamedParameters = initParams(namedParams, resolver); if (cachedReturnType == null) { if (resolver != null) { cachedReturnType = resolver.resolve(returnType); } else { cachedReturnType = VariableScope.OBJECT_CLASS_NODE; } } } MethodNode meth = new NamedArgsMethodNode( methodName, opcode(), cachedReturnType, cachedRegularParameters, cachedNamedParameters, cachedOptionalParameters, NO_EXCEPTIONS, EMPTY_BLOCK); meth.setDeclaringClass(ensureDeclaringType(declaringType, resolver)); return meth; }
public static void visitScriptCode(SourceUnit source, GroovyCodeVisitor transformer) { source.getAST().getStatementBlock().visit(transformer); for (Object method : source.getAST().getMethods()) { MethodNode methodNode = (MethodNode) method; methodNode.getCode().visit(transformer); } }
public static String makeDescriptorWithoutReturnType(MethodNode mn) { StringBuilder sb = new StringBuilder(); sb.append(mn.getName()).append(':'); for (Parameter p : mn.getParameters()) { sb.append(p.getType()).append(','); } return sb.toString(); }
private AnnotatedNode createMethodDeclaration( String finderName, String[] props, String[] comparators, String newPropName, String newComparator) { // need to determine number of parameters // first figure out how many properties we need to look at int numArgs = -1; if (newPropName != null) { for (int i = 0; i < props.length; i++) { if (props[i] == null) { props[i] = newPropName; numArgs = i + 1; break; } } } if (newComparator != null) { for (int i = 0; i < comparators.length; i++) { if (comparators[i] == null) { comparators[i] = newComparator; numArgs = i + 1; break; } } } List<Parameter> params = new ArrayList<Parameter>(2); // now go through each component and comparator. // determine the kind of parameters they require for (int i = 0; i < numArgs; i++) { ClassNode[] classNodes = COMPARATOR_ARGUMENT_MAP.get(comparators[i]); if (classNodes.length > 0) { String uncapitalized = uncapitalize(props[i]); params.add(new Parameter(classNodes[0], uncapitalized)); if (classNodes.length == 2) { params.add(new Parameter(classNodes[1], uncapitalized + "1")); } } } MethodNode method = new MethodNode( finderName, Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, createReturnType(finderName), params.toArray(new Parameter[params.size()]), NO_EXCEPTIONS, EMPTY_BLOCK); if (domain != null) { method.setDeclaringClass(domain.getGroovyClass()); } else { method.setDeclaringClass(VariableScope.OBJECT_CLASS_NODE); } return method; }
private void checkMethodModifiers(MethodNode node) { // don't check volatile here as it overlaps with ACC_BRIDGE // additional modifiers not allowed for interfaces if ((this.currentClass.getModifiers() & ACC_INTERFACE) != 0) { checkMethodForModifier(node, isStrict(node.getModifiers()), "strictfp"); checkMethodForModifier(node, isSynchronized(node.getModifiers()), "synchronized"); checkMethodForModifier(node, isNative(node.getModifiers()), "native"); } }
private void memorizeInitialExpressions(final MethodNode node) { // add node metadata for default parameters because they are erased by the Verifier if (node.getParameters() != null) { for (Parameter parameter : node.getParameters()) { parameter.putNodeMetaData( StaticTypesMarker.INITIAL_EXPRESSION, parameter.getInitialExpression()); } } }
public static boolean hasDeclaredMethod(ClassNode cNode, String name, int argsCount) { List<MethodNode> ms = cNode.getDeclaredMethods(name); for (MethodNode m : ms) { Parameter[] paras = m.getParameters(); if (paras != null && paras.length == argsCount) { return true; } } return false; }
public static boolean isConstructorMethod(MethodNode declaredMethod) { return declaredMethod.isStatic() && declaredMethod.isPublic() && declaredMethod.getName().equals("initialize") && declaredMethod.getParameters().length >= 1 && declaredMethod .getParameters()[0] .getType() .equals(AbstractGrailsArtefactTransformer.OBJECT_CLASS); }
private void visitMethodNode(MethodNode methodNode) { if (methodNode.isSyntheticPublic()) revertVisibility(methodNode); else throw new RuntimeException( "Can't use " + MY_TYPE_NAME + " for method '" + methodNode.getName() + "' which has explicit visibility."); }
// no rename so delete and add private static void renameMethod(ClassNode buildee, MethodNode mNode, String newName) { buildee.addMethod( newName, mNode.getModifiers(), mNode.getReturnType(), mNode.getParameters(), mNode.getExceptions(), mNode.getCode()); buildee.removeMethod(mNode); }
/** * 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); } }
public void visitMethod(MethodNode node) { inConstructor = false; inStaticConstructor = node.isStaticConstructor(); checkAbstractDeclaration(node); checkRepetitiveMethod(node); checkOverloadingPrivateAndPublic(node); checkMethodModifiers(node); checkGenericsUsage(node, node.getParameters()); checkGenericsUsage(node, node.getReturnType()); super.visitMethod(node); }
/** * Tests whether the ClassNode implements the specified method name * * @param classNode The ClassNode * @param methodName The method name * @param argTypes * @return True if it implements the method */ private static boolean implementsMethod( ClassNode classNode, String methodName, Class[] argTypes) { List methods = classNode.getMethods(); for (Iterator i = methods.iterator(); i.hasNext(); ) { MethodNode mn = (MethodNode) i.next(); final boolean isZeroArg = (argTypes == null || argTypes.length == 0); boolean methodMatch = mn.getName().equals(methodName) && isZeroArg; if (methodMatch) return true; // TODO Implement further parameter analysis } return false; }
private void checkAbstractDeclaration(MethodNode methodNode) { if (!methodNode.isAbstract()) return; if (isAbstract(currentClass.getModifiers())) return; addError( "Can't have an abstract method in a non-abstract class." + " The " + getDescription(currentClass) + " must be declared abstract or the method '" + methodNode.getTypeDescriptor() + "' must not be abstract.", methodNode); }
@Test public void transformationOfAnnotationOnMethod() { ClassNode classNode = new ClassNode("Test", 0, new ClassNode(Object.class)); this.moduleNode.addClass(classNode); MethodNode methodNode = new MethodNode( "test", 0, new ClassNode(Void.class), new Parameter[0], new ClassNode[0], null); methodNode.addAnnotation(this.grabAnnotation); classNode.addMethod(methodNode); assertGrabAnnotationHasBeenTransformed(); }
private void changeBaseScriptType( final AnnotatedNode parent, final ClassNode cNode, final ClassNode baseScriptType) { if (!cNode.isScriptBody()) { addError("Annotation " + MY_TYPE_NAME + " can only be used within a Script.", parent); return; } if (!baseScriptType.isScript()) { addError( "Declared type " + baseScriptType + " does not extend groovy.lang.Script class!", parent); return; } cNode.setSuperClass(baseScriptType); // Method in base script that will contain the script body code. MethodNode runScriptMethod = ClassHelper.findSAM(baseScriptType); // If they want to use a name other than than "run", then make the change. if (isCustomScriptBodyMethod(runScriptMethod)) { MethodNode defaultMethod = cNode.getDeclaredMethod("run", Parameter.EMPTY_ARRAY); // GROOVY-6706: Sometimes an NPE is thrown here. // The reason is that our transform is getting called more than once sometimes. if (defaultMethod != null) { cNode.removeMethod(defaultMethod); MethodNode methodNode = new MethodNode( runScriptMethod.getName(), runScriptMethod.getModifiers() & ~ACC_ABSTRACT, runScriptMethod.getReturnType(), runScriptMethod.getParameters(), runScriptMethod.getExceptions(), defaultMethod.getCode()); // The AST node metadata has the flag that indicates that this method is a script body. // It may also be carrying data for other AST transforms. methodNode.copyNodeMetaData(defaultMethod); cNode.addMethod(methodNode); } } // If the new script base class does not have a contextual constructor (g.l.Binding), then we // won't either. // We have to do things this way (and rely on just default constructors) because the logic that // generates // the constructors for our script class have already run. if (cNode.getSuperClass().getDeclaredConstructor(CONTEXT_CTOR_PARAMETERS) == null) { ConstructorNode orphanedConstructor = cNode.getDeclaredConstructor(CONTEXT_CTOR_PARAMETERS); cNode.removeConstructor(orphanedConstructor); } }
private MethodNode createBuildMethodForMethod( AnnotationNode anno, ClassNode buildee, MethodNode mNode, Parameter[] params) { String buildMethodName = getMemberStringValue(anno, "buildMethodName", "build"); final BlockStatement body = new BlockStatement(); ClassNode returnType; if (mNode instanceof ConstructorNode) { returnType = newClass(buildee); body.addStatement(returnS(ctorX(newClass(mNode.getDeclaringClass()), args(params)))); } else { body.addStatement( returnS(callX(newClass(mNode.getDeclaringClass()), mNode.getName(), args(params)))); returnType = newClass(mNode.getReturnType()); } return new MethodNode(buildMethodName, ACC_PUBLIC, returnType, NO_PARAMS, NO_EXCEPTIONS, body); }
private void visitDeprecation(AnnotatedNode node, AnnotationNode visited) { if (visited.getClassNode().isResolved() && visited.getClassNode().getName().equals("java.lang.Deprecated")) { if (node instanceof MethodNode) { MethodNode mn = (MethodNode) node; mn.setModifiers(mn.getModifiers() | Opcodes.ACC_DEPRECATED); } else if (node instanceof FieldNode) { FieldNode fn = (FieldNode) node; fn.setModifiers(fn.getModifiers() | Opcodes.ACC_DEPRECATED); } else if (node instanceof ClassNode) { ClassNode cn = (ClassNode) node; cn.setModifiers(cn.getModifiers() | Opcodes.ACC_DEPRECATED); } } }
private String getPropertyName(MethodNode m) { String name = m.getName(); if (!(name.startsWith("set") || name.startsWith("get"))) return null; String pname = name.substring(3); if (pname.length() == 0) return null; pname = java.beans.Introspector.decapitalize(pname); if (name.startsWith("get") && (m.getReturnType() == ClassHelper.VOID_TYPE || m.getParameters().length != 0)) { return null; } if (name.startsWith("set") && m.getParameters().length != 1) { return null; } return pname; }
private static VariableExpression addApiVariableDeclaration( Expression delegate, MethodNode declaredMethod, BlockStatement methodBody) { VariableExpression apiVar = new VariableExpression("$api_" + declaredMethod.getName()); DeclarationExpression de = new DeclarationExpression(apiVar, ASSIGNMENT_OPERATOR, delegate); methodBody.addStatement(new ExpressionStatement(de)); return apiVar; }
public static boolean isCandidateInstanceMethod(ClassNode classNode, MethodNode declaredMethod) { Parameter[] parameterTypes = declaredMethod.getParameters(); return isCandidateMethod(declaredMethod) && parameterTypes != null && parameterTypes.length > 0 && isAssignableFrom(parameterTypes[0].getType(), classNode); }
@Override public void visitMethod(final MethodNode node) { if (isSkipMode(node)) { node.putNodeMetaData(STATIC_COMPILE_NODE, false); } super.visitMethod(node); checkForConstructorWithCSButClassWithout(node); }