C++程序  |  267行  |  6.66 KB

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Method.h"

#include "Annotation.h"
#include "ScalarType.h"
#include "Type.h"

#include <android-base/logging.h>
#include <hidl-util/Formatter.h>

namespace android {

Method::Method(const char *name,
       std::vector<TypedVar *> *args,
       std::vector<TypedVar *> *results,
       bool oneway,
       std::vector<Annotation *> *annotations)
    : mName(name),
      mArgs(args),
      mResults(results),
      mOneway(oneway),
      mAnnotations(annotations) {
}

void Method::fillImplementation(
        size_t serial,
        MethodImpl cppImpl,
        MethodImpl javaImpl) {
    mIsHidlReserved = true;
    mSerial = serial;
    mCppImpl = cppImpl;
    mJavaImpl = javaImpl;

    CHECK(mJavaImpl.find(IMPL_STUB_IMPL) == mJavaImpl.end())
            << "FATAL: mJavaImpl should not use IMPL_STUB_IMPL; use IMPL_INTERFACE instead.";
    CHECK(mCppImpl.find(IMPL_STUB_IMPL) == mCppImpl.end() ||
          mCppImpl.find(IMPL_STUB) == mCppImpl.end())
            << "FATAL: mCppImpl IMPL_STUB will override IMPL_STUB_IMPL.";
}

std::string Method::name() const {
    return mName;
}

const std::vector<TypedVar *> &Method::args() const {
    return *mArgs;
}

const std::vector<TypedVar *> &Method::results() const {
    return *mResults;
}

const std::vector<Annotation *> &Method::annotations() const {
    return *mAnnotations;
}

void Method::cppImpl(MethodImplType type, Formatter &out) const {
    CHECK(mIsHidlReserved);
    auto it = mCppImpl.find(type);
    if (it != mCppImpl.end()) {
        if (it->second != nullptr) {
            it->second(out);
        }
    }
}

void Method::javaImpl(MethodImplType type, Formatter &out) const {
    CHECK(mIsHidlReserved);
    auto it = mJavaImpl.find(type);
    if (it != mJavaImpl.end()) {
        if (it->second != nullptr) {
            it->second(out);
        }
    }
}

bool Method::isHiddenFromJava() const {
    return isHidlReserved() && name() == "debug";
}

bool Method::overridesCppImpl(MethodImplType type) const {
    CHECK(mIsHidlReserved);
    return mCppImpl.find(type) != mCppImpl.end();
}

bool Method::overridesJavaImpl(MethodImplType type) const {
    CHECK(mIsHidlReserved);
    return mJavaImpl.find(type) != mJavaImpl.end();
}

Method *Method::copySignature() const {
    return new Method(mName.c_str(), mArgs, mResults, mOneway, mAnnotations);
}

void Method::setSerialId(size_t serial) {
    CHECK(!mIsHidlReserved);
    mSerial = serial;
}

size_t Method::getSerialId() const {
    return mSerial;
}

void Method::generateCppSignature(Formatter &out,
                                  const std::string &className,
                                  bool specifyNamespaces) const {
    const bool returnsValue = !results().empty();

    const TypedVar *elidedReturn = canElideCallback();

    std::string space = (specifyNamespaces ? "::android::hardware::" : "");

    if (elidedReturn == nullptr) {
        out << space << "Return<void> ";
    } else {
        out << space
            << "Return<"
            << elidedReturn->type().getCppResultType( specifyNamespaces)
            << "> ";
    }

    if (!className.empty()) {
        out << className << "::";
    }

    out << name()
        << "(";
    emitCppArgSignature(out, specifyNamespaces);

    if (returnsValue && elidedReturn == nullptr) {
        if (!args().empty()) {
            out << ", ";
        }

        out << name() << "_cb _hidl_cb";
    }

    out << ")";
}

static void emitCppArgResultSignature(Formatter &out,
                         const std::vector<TypedVar *> &args,
                         bool specifyNamespaces) {
    out.join(args.begin(), args.end(), ", ", [&](auto arg) {
        out << arg->type().getCppArgumentType(specifyNamespaces);
        out << " ";
        out << arg->name();
    });
}

static void emitJavaArgResultSignature(Formatter &out, const std::vector<TypedVar *> &args) {
    out.join(args.begin(), args.end(), ", ", [&](auto arg) {
        out << arg->type().getJavaType();
        out << " ";
        out << arg->name();
    });
}

void Method::emitCppArgSignature(Formatter &out, bool specifyNamespaces) const {
    emitCppArgResultSignature(out, args(), specifyNamespaces);
}
void Method::emitCppResultSignature(Formatter &out, bool specifyNamespaces) const {
    emitCppArgResultSignature(out, results(), specifyNamespaces);
}
void Method::emitJavaArgSignature(Formatter &out) const {
    emitJavaArgResultSignature(out, args());
}
void Method::emitJavaResultSignature(Formatter &out) const {
    emitJavaArgResultSignature(out, results());
}

void Method::dumpAnnotations(Formatter &out) const {
    if (mAnnotations->size() == 0) {
        return;
    }

    out << "// ";
    for (size_t i = 0; i < mAnnotations->size(); ++i) {
        if (i > 0) {
            out << " ";
        }
        mAnnotations->at(i)->dump(out);
    }
    out << "\n";
}

bool Method::isJavaCompatible() const {
    if (isHiddenFromJava()) {
        return true;
    }

    for (const auto &arg : *mArgs) {
        if (!arg->isJavaCompatible()) {
            return false;
        }
    }

    for (const auto &result : *mResults) {
        if (!result->isJavaCompatible()) {
            return false;
        }
    }

    return true;
}

const TypedVar* Method::canElideCallback() const {
    // Can't elide callback for void or tuple-returning methods
    if (mResults->size() != 1) {
        return nullptr;
    }

    const TypedVar *typedVar = mResults->at(0);

    if (typedVar->type().isElidableType()) {
        return typedVar;
    }

    return nullptr;
}

////////////////////////////////////////////////////////////////////////////////

TypedVar::TypedVar(const char *name, Type *type)
    : mName(name),
      mType(type) {
}

std::string TypedVar::name() const {
    return mName;
}

const Type &TypedVar::type() const {
    return *mType;
}

bool TypedVar::isJavaCompatible() const {
    return mType->isJavaCompatible();
}

////////////////////////////////////////////////////////////////////////////////
bool TypedVarVector::add(TypedVar *v) {
    if (mNames.emplace(v->name()).second) {
        push_back(v);
        return true;
    }
    return false;
}

}  // namespace android