static void
generate_method(const method_type* method, Class* interface,
                    StubClass* stubClass, ProxyClass* proxyClass, int index)
{
    arg_type* arg;
    int i;
    bool hasOutParams = false;

    const bool oneway = proxyClass->mOneWay || method->oneway;

    // == the TRANSACT_ constant =============================================
    string transactCodeName = "TRANSACTION_";
    transactCodeName += method->name.data;

    //char transactCodeValue[60];
    //sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);

    //Field* transactCode = new Field(STATIC | FINAL,
    //                        new Variable(INT_TYPE, transactCodeName));
    //transactCode->value = transactCodeValue;
    //interface->elements.push_back(transactCode);

    if (interface->methodEnum == 0) interface->methodEnum = new Enum();
    EnumItem* item = new EnumItem();
    item->name = transactCodeName;
    if (interface->methodEnum->items.size() == 0) item->value = "IBinder::FIRST_CALL_TRANSACTION";
    else item->value = "";
    interface->methodEnum->items.push_back(item);
    interface->declareMetaInterfaceName = string(interface->type->Name().c_str() + 1);
    interface->implementMetaInterfaceName = string(interface->type->Name().c_str() + 1);

    // +JDN
    //interface->implementMetaInterfaceDesc = interface->type->CPPQualifiedName();
    interface->implementMetaInterfaceDesc = interface->type->QualifiedName();
    // -JDN

    // == the declaration in the interface ===================================
    Method* decl = new Method;
        decl->comment = gather_comments(method->comments_token->extra);
        decl->modifiers = VIRTUAL;
        decl->returnType = NAMES.Search(method->type.type.data);
        decl->returnTypeDimension = method->type.dimension;
        decl->name = method->name.data;

    arg = method->args;
    while (arg != NULL) {
        Type* vType = NAMES.Search(arg->type.type.data);
        Variable* v = new Variable(
                    vType, arg->name.data,
                    arg->type.dimension);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(vType);
        if (userDataType != NULL) {
            v->modifiers = POINTER;
        }
        decl->parameters.push_back(v);
        arg = arg->next;
    }

    // No exception in C++
    //decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);

    interface->elements.push_back(decl);

    // == the stub method ====================================================

    Case* c = new Case(transactCodeName);

    Variable* thisVar = new Variable(interface->type, "this");
    thisVar->modifiers = POINTER;
    MethodCall* realCall = new MethodCall(thisVar/*THIS_VALUE*/, method->name.data);

    // interface token validation is the very first thing we do

    string getDescriptor = interface->type->Name() + string("::getInterfaceDescriptor()");

    // +JDN Don t do checkInterface + enforceInterface it broke serialization
    // c->statements->Add(new MethodCall(stubClass->transact_data,
    //        "enforceInterface", 1, new LiteralExpression(getDescriptor/*"DESCRIPTOR"*/)));
    // -JDN

    // args
    Variable* cl = NULL;
    VariableFactory stubArgs("_arg");
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(t);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(t);
        InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(t);
        if (userDataType != NULL) v->modifiers |= POINTER;
        else if (interfaceType != NULL) v->modifiers |= STRONG_POINTER;
        //if (userDataType != NULL) v->modifiers |= CALL_POINTER;
        v->dimension = arg->type.dimension;

        c->statements->Add(new VariableDeclaration(v));

        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
            generate_create_from_parcel(t, c->statements, v,
                    stubClass->transact_data, &cl);
        } else {
            if (arg->type.dimension == 0) {
                c->statements->Add(new Assignment(v, new NewExpression(v->type)));
            }
            else if (arg->type.dimension == 1) {
                generate_new_array(v->type, c->statements, v,
                        stubClass->transact_data);
            }
            else {
                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
                        __LINE__);
            }
        }

        realCall->arguments.push_back(v);

        arg = arg->next;
    }

    // the real call
    Variable* _result = NULL;
    if (0 == strcmp(method->type.type.data, "void")) {
        c->statements->Add(realCall);

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }
    } else {
        _result = new Variable(decl->returnType, "_result",
                                decl->returnTypeDimension);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(decl->returnType);
        InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(decl->returnType);
        if (userDataType != NULL) _result->modifiers = POINTER;
        else if (interfaceType != NULL) _result->modifiers = STRONG_POINTER;
        c->statements->Add(new VariableDeclaration(_result, realCall));

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }

        // marshall the return value
        generate_write_to_parcel(decl->returnType, c->statements, _result,
                                    stubClass->transact_reply,
                                    Type::PARCELABLE_WRITE_RETURN_VALUE);
    }

    // out parameters
    i = 0;
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(i++);

        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
            generate_write_to_parcel(t, c->statements, v,
                                stubClass->transact_reply,
                                Type::PARCELABLE_WRITE_RETURN_VALUE);
            hasOutParams = true;
        }

        arg = arg->next;
    }

    // return true
    c->statements->Add(new ReturnStatement(new LiteralExpression("NO_ERROR")));
    stubClass->transact_switch->cases.push_back(c);

    // == the proxy method ===================================================
    Method* proxy = new Method;
        proxy->comment = gather_comments(method->comments_token->extra);
        proxy->modifiers = PUBLIC | OVERRIDE;
        proxy->returnType = NAMES.Search(method->type.type.data);
        proxy->returnTypeDimension = method->type.dimension;
        proxy->name = method->name.data;
        proxy->statements = new StatementBlock;
        proxy->classType = proxyClass->type;
        arg = method->args;
        while (arg != NULL) {
            Type* vType = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(
                        vType, arg->name.data,
                        arg->type.dimension);
            UserDataType* userDataType = dynamic_cast<UserDataType*>(vType);
            InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(vType);
            if (userDataType != NULL) {
                v->modifiers |= POINTER;
            } else if (interfaceType != NULL) {
                v->modifiers |= STRONG_POINTER;
            }
            proxy->parameters.push_back(v/*new Variable(
                            NAMES.Search(arg->type.type.data), arg->name.data,
                            arg->type.dimension)*/);
            arg = arg->next;
        }
        //proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
    proxyClass->elements.push_back(proxy);

    // the parcels
    Variable* _data = new Variable(PARCEL_TYPE, "_data");
    //proxy->statements->Add(new VariableDeclaration(_data,
    //                            new MethodCall(PARCEL_TYPE, "obtain")));
    proxy->statements->Add(new VariableDeclaration(_data));

    Variable* _reply = NULL;
    if (!oneway) {
        _reply = new Variable(PARCEL_TYPE, "_reply");
        //proxy->statements->Add(new VariableDeclaration(_reply,
        //                            new MethodCall(PARCEL_TYPE, "obtain")));
        proxy->statements->Add(new VariableDeclaration(_reply));
    }

    // the return value
    _result = NULL;
    if (0 != strcmp(method->type.type.data, "void")) {
        _result = new Variable(proxy->returnType, "_result",
                method->type.dimension);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(proxy->returnType);
        InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(proxy->returnType);
        if (userDataType != NULL) {
            _result->modifiers = POINTER;
        } else if (interfaceType != NULL) {
            _result->modifiers = STRONG_POINTER;
        }
        proxy->statements->Add(new VariableDeclaration(_result));
    }

    // try and finally
    //TryStatement* tryStatement = new TryStatement();
    //proxy->statements->Add(tryStatement);
    //FinallyStatement* finallyStatement = new FinallyStatement();
    //proxy->statements->Add(finallyStatement);

    // the interface identifier token: the DESCRIPTOR constant, marshalled as a string

    /*tryStatement*/proxy->statements->Add(new MethodCall(_data, "writeInterfaceToken",
            1, new LiteralExpression(getDescriptor/*"DESCRIPTOR"*/)));

    // the parameters
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
        int dir = convert_direction(arg->direction.data);
        v->modifiers |= POINTER;
        if (dir == OUT_PARAMETER && arg->type.dimension != 0)
		{
            IfStatement* checklen = new IfStatement();
            checklen->expression = new Comparison(v, "==", NULL_VALUE);
            checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
                        new LiteralExpression("-1")));
            checklen->elseif = new IfStatement();
            checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
                        1, new FieldVariable(v, "length")));
            /*tryStatement*/proxy->statements->Add(checklen);
        }
        else if (dir & IN_PARAMETER)
        {
            // +JDN
            // ALERT LEAK !!!!
            Variable* localParcel = new Variable();
            localParcel->type = _data->type;
            localParcel->name = _data->name;
            localParcel->dimension = _data->dimension;
            localParcel->modifiers = _data->modifiers;
            localParcel->modifiers |= CALL_REFERENCE;
            // printf("generating parcel for %s (%s)\n", v->name.c_str(), v->type->Name().c_str());
            //generate_write_to_parcel(t, /*tryStatement*/proxy->statements, v, _data, 0);
            generate_write_to_parcel(t, /*tryStatement*/proxy->statements, v, localParcel, 0);
            // -JDN
        }
        else
        {
            // printf("else\n", "");
            // Do nothing
        }
        arg = arg->next;
    }

    // the transact call
    Variable* callReply = NULL;
    if (_reply != NULL) {
        callReply = new Variable(_reply->type, _reply->name);
        callReply->modifiers = CALL_REFERENCE;
    }
    MethodCall* call = new MethodCall(/*proxyClass->mRemote*/ new LiteralExpression("(*(remote()))"), "transact", 4,
                            new LiteralExpression(/*"Stub." +*/ transactCodeName),
                            _data, callReply ? callReply : NULL_VALUE,
                            new LiteralExpression(
                                          oneway ? /*"android.os.IBinder.FLAG_ONEWAY"*/ "IBinder::FLAG_ONEWAY" : "0"));
    /*tryStatement*/proxy->statements->Add(call);

    // throw back exceptions.
    if (_reply) {
        MethodCall* ex = new MethodCall(_reply, "readExceptionCode", 0);
        /*tryStatement*/proxy->statements->Add(ex);
    }

    // returning and cleanup
    if (_reply != NULL) {
        if (_result != NULL) {
            generate_create_from_parcel(proxy->returnType,
                    /*tryStatement*/proxy->statements, _result, _reply, &cl);
        }

        // the out/inout parameters
        arg = method->args;
        while (arg != NULL) {
            Type* t = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
            UserDataType* userDataType = dynamic_cast<UserDataType*>(t);
            if (userDataType != NULL) v->modifiers = POINTER;
            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
                generate_read_from_parcel(t, /*tryStatement*/proxy->statements,
                                            v, _reply, &cl);
            }
            arg = arg->next;
        }

        //finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
    }
    //finallyStatement->statements->Add(new MethodCall(_data, "recycle"));

    if (_result != NULL) {
        proxy->statements->Add(new ReturnStatement(_result));
    }
}
static void
generate_method(const method_type* method, Class* interface,
                    StubClass* stubClass, ProxyClass* proxyClass, int index)
{
    arg_type* arg;
    int i;
    bool hasOutParams = false;

    const bool oneway = proxyClass->mOneWay || method->oneway;

    // == the TRANSACT_ constant =============================================
    string transactCodeName = "TRANSACTION_";
    transactCodeName += method->name.data;

    char transactCodeValue[50];
    sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);

    Field* transactCode = new Field(STATIC | FINAL,
                            new Variable(INT_TYPE, transactCodeName));
    transactCode->value = transactCodeValue;
    stubClass->elements.push_back(transactCode);

    // == the declaration in the interface ===================================
    Method* decl = new Method;
        decl->comment = gather_comments(method->comments_token->extra);
        decl->modifiers = PUBLIC;
        decl->returnType = NAMES.Search(method->type.type.data);
        decl->returnTypeDimension = method->type.dimension;
        decl->name = method->name.data;

    arg = method->args;
    while (arg != NULL) {
        decl->parameters.push_back(new Variable(
                            NAMES.Search(arg->type.type.data), arg->name.data,
                            arg->type.dimension));
        arg = arg->next;
    }

    decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);

    interface->elements.push_back(decl);

    // == the stub method ====================================================

    Case* c = new Case(transactCodeName);

    MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);

    // interface token validation is the very first thing we do
    c->statements->Add(new MethodCall(stubClass->transact_data,
            "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));

    // args
    Variable* cl = NULL;
    VariableFactory stubArgs("_arg");
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(t);
        v->dimension = arg->type.dimension;

        c->statements->Add(new VariableDeclaration(v));

        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
            generate_create_from_parcel(t, c->statements, v,
                    stubClass->transact_data, &cl);
        } else {
            if (arg->type.dimension == 0) {
                c->statements->Add(new Assignment(
                                                v, new NewExpression(v->type)));
            }
            else if (arg->type.dimension == 1) {
                generate_new_array(v->type, c->statements, v,
                        stubClass->transact_data);
            }
            else {
                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
                        __LINE__);
            }
        }

        realCall->arguments.push_back(v);

        arg = arg->next;
    }

    // the real call
    Variable* _result = NULL;
    if (0 == strcmp(method->type.type.data, "void")) {
        c->statements->Add(realCall);

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }
    } else {
        _result = new Variable(decl->returnType, "_result",
                                decl->returnTypeDimension);
        c->statements->Add(new VariableDeclaration(_result, realCall));

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }

        // marshall the return value
        generate_write_to_parcel(decl->returnType, c->statements, _result,
                                    stubClass->transact_reply,
                                    Type::PARCELABLE_WRITE_RETURN_VALUE);
    }

    // out parameters
    i = 0;
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(i++);

        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
            generate_write_to_parcel(t, c->statements, v,
                                stubClass->transact_reply,
                                Type::PARCELABLE_WRITE_RETURN_VALUE);
            hasOutParams = true;
        }

        arg = arg->next;
    }

    // return true
    c->statements->Add(new ReturnStatement(TRUE_VALUE));
    stubClass->transact_switch->cases.push_back(c);

    // == the proxy method ===================================================
    Method* proxy = new Method;
        proxy->comment = gather_comments(method->comments_token->extra);
        proxy->modifiers = PUBLIC;
        proxy->returnType = NAMES.Search(method->type.type.data);
        proxy->returnTypeDimension = method->type.dimension;
        proxy->name = method->name.data;
        proxy->statements = new StatementBlock;
        arg = method->args;
        while (arg != NULL) {
            proxy->parameters.push_back(new Variable(
                            NAMES.Search(arg->type.type.data), arg->name.data,
                            arg->type.dimension));
            arg = arg->next;
        }
        proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
    proxyClass->elements.push_back(proxy);

    // the parcels
    Variable* _data = new Variable(PARCEL_TYPE, "_data");
    proxy->statements->Add(new VariableDeclaration(_data,
                                new MethodCall(PARCEL_TYPE, "obtain")));
    Variable* _reply = NULL;
    if (!oneway) {
        _reply = new Variable(PARCEL_TYPE, "_reply");
        proxy->statements->Add(new VariableDeclaration(_reply,
                                    new MethodCall(PARCEL_TYPE, "obtain")));
    }

    // the return value
    _result = NULL;
    if (0 != strcmp(method->type.type.data, "void")) {
        _result = new Variable(proxy->returnType, "_result",
                method->type.dimension);
        proxy->statements->Add(new VariableDeclaration(_result));
    }

    // try and finally
    TryStatement* tryStatement = new TryStatement();
    proxy->statements->Add(tryStatement);
    FinallyStatement* finallyStatement = new FinallyStatement();
    proxy->statements->Add(finallyStatement);

    // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
    tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
            1, new LiteralExpression("DESCRIPTOR")));

    // the parameters
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
        int dir = convert_direction(arg->direction.data);
        if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
            IfStatement* checklen = new IfStatement();
            checklen->expression = new Comparison(v, "==", NULL_VALUE);
            checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
                        new LiteralExpression("-1")));
            checklen->elseif = new IfStatement();
            checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
                        1, new FieldVariable(v, "length")));
            tryStatement->statements->Add(checklen);
        }
        else if (dir & IN_PARAMETER) {
            generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
        }
        arg = arg->next;
    }

    // the transact call
    MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
                            new LiteralExpression("Stub." + transactCodeName),
                            _data, _reply ? _reply : NULL_VALUE,
                            new LiteralExpression(
                                oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
    tryStatement->statements->Add(call);

    // throw back exceptions.
    if (_reply) {
        MethodCall* ex = new MethodCall(_reply, "readException", 0);
        tryStatement->statements->Add(ex);
    }

    // returning and cleanup
    if (_reply != NULL) {
        if (_result != NULL) {
            generate_create_from_parcel(proxy->returnType,
                    tryStatement->statements, _result, _reply, &cl);
        }

        // the out/inout parameters
        arg = method->args;
        while (arg != NULL) {
            Type* t = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
                generate_read_from_parcel(t, tryStatement->statements,
                                            v, _reply, &cl);
            }
            arg = arg->next;
        }

        finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
    }
    finallyStatement->statements->Add(new MethodCall(_data, "recycle"));

    if (_result != NULL) {
        proxy->statements->Add(new ReturnStatement(_result));
    }
}