/** * 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); } }
@Override public void visitMethodCallExpression(final MethodCallExpression call) { super.visitMethodCallExpression(call); MethodNode target = (MethodNode) call.getNodeMetaData(DIRECT_METHOD_CALL_TARGET); if (target != null) { call.setMethodTarget(target); memorizeInitialExpressions(target); } if (call.getMethodTarget() == null && call.getLineNumber() > 0) { addError("Target method for method call expression hasn't been set", call); } }