/** * 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); } }
/** * If constructor does not define a call to super, then transform constructor to get String,int * parameters at beginning and add call super(String,int). */ private void transformConstructor(ConstructorNode ctor, boolean isAic) { boolean chainedThisConstructorCall = false; ConstructorCallExpression cce = null; if (ctor.firstStatementIsSpecialConstructorCall()) { Statement code = ctor.getFirstStatement(); cce = (ConstructorCallExpression) ((ExpressionStatement) code).getExpression(); if (cce.isSuperCall()) return; // must be call to this(...) chainedThisConstructorCall = true; } // we need to add parameters Parameter[] oldP = ctor.getParameters(); Parameter[] newP = new Parameter[oldP.length + 2]; String stringParameterName = getUniqueVariableName("__str", ctor.getCode()); newP[0] = new Parameter(ClassHelper.STRING_TYPE, stringParameterName); String intParameterName = getUniqueVariableName("__int", ctor.getCode()); newP[1] = new Parameter(ClassHelper.int_TYPE, intParameterName); System.arraycopy(oldP, 0, newP, 2, oldP.length); ctor.setParameters(newP); VariableExpression stringVariable = new VariableExpression(newP[0]); VariableExpression intVariable = new VariableExpression(newP[1]); if (chainedThisConstructorCall) { TupleExpression args = (TupleExpression) cce.getArguments(); List<Expression> argsExprs = args.getExpressions(); argsExprs.add(0, stringVariable); argsExprs.add(1, intVariable); } else { // add a super call List<Expression> args = new ArrayList<Expression>(); args.add(stringVariable); args.add(intVariable); if (isAic) { for (Parameter parameter : oldP) { args.add(new VariableExpression(parameter.getName())); } } cce = new ConstructorCallExpression(ClassNode.SUPER, new ArgumentListExpression(args)); BlockStatement code = new BlockStatement(); code.addStatement(new ExpressionStatement(cce)); Statement oldCode = ctor.getCode(); if (oldCode != null) code.addStatement(oldCode); ctor.setCode(code); } }