| /* |
| * 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> |
| #include <algorithm> |
| |
| namespace android { |
| |
| Method::Method(const char* name, std::vector<NamedReference<Type>*>* args, |
| std::vector<NamedReference<Type>*>* results, bool oneway, |
| std::vector<Annotation*>* annotations, const Location& location) |
| : mName(name), |
| mArgs(args), |
| mResults(results), |
| mOneway(oneway), |
| mAnnotations(annotations), |
| mLocation(location) {} |
| |
| 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<NamedReference<Type>*>& Method::args() const { |
| return *mArgs; |
| } |
| |
| const std::vector<NamedReference<Type>*>& Method::results() const { |
| return *mResults; |
| } |
| |
| const std::vector<Annotation *> &Method::annotations() const { |
| return *mAnnotations; |
| } |
| |
| std::vector<Reference<Type>> Method::getReferences() const { |
| std::vector<Reference<Type>> ret; |
| for (const auto* arg : *mArgs) { |
| ret.push_back(*arg); |
| } |
| for (const auto* result : *mResults) { |
| ret.push_back(*result); |
| } |
| return ret; |
| } |
| |
| status_t Method::evaluate() { |
| for (auto* annotaion : *mAnnotations) { |
| status_t err = annotaion->evaluate(); |
| if (err != OK) return err; |
| } |
| |
| return OK; |
| } |
| |
| status_t Method::validate() const { |
| for (const auto* annotaion : *mAnnotations) { |
| status_t err = annotaion->validate(); |
| if (err != OK) return err; |
| } |
| |
| return OK; |
| } |
| |
| 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, Location()); |
| } |
| |
| void Method::setSerialId(size_t serial) { |
| CHECK(!mIsHidlReserved); |
| mSerial = serial; |
| } |
| |
| size_t Method::getSerialId() const { |
| return mSerial; |
| } |
| |
| bool Method::hasEmptyCppArgSignature() const { |
| return args().empty() && (results().empty() || canElideCallback() != nullptr); |
| } |
| |
| void Method::generateCppReturnType(Formatter &out, bool specifyNamespaces) const { |
| const NamedReference<Type>* elidedReturn = canElideCallback(); |
| const std::string space = (specifyNamespaces ? "::android::hardware::" : ""); |
| |
| if (elidedReturn == nullptr) { |
| out << space << "Return<void> "; |
| } else { |
| out << space |
| << "Return<" |
| << elidedReturn->type().getCppResultType( specifyNamespaces) |
| << "> "; |
| } |
| } |
| |
| void Method::generateCppSignature(Formatter &out, |
| const std::string &className, |
| bool specifyNamespaces) const { |
| generateCppReturnType(out, specifyNamespaces); |
| |
| if (!className.empty()) { |
| out << className << "::"; |
| } |
| |
| out << name() |
| << "("; |
| emitCppArgSignature(out, specifyNamespaces); |
| out << ")"; |
| } |
| |
| static void emitCppArgResultSignature(Formatter& out, |
| const std::vector<NamedReference<Type>*>& 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<NamedReference<Type>*>& 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); |
| |
| const bool returnsValue = !results().empty(); |
| const NamedReference<Type>* elidedReturn = canElideCallback(); |
| if (returnsValue && elidedReturn == nullptr) { |
| if (!args().empty()) { |
| out << ", "; |
| } |
| |
| out << name() << "_cb _hidl_cb"; |
| } |
| } |
| 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; |
| } |
| |
| if (!std::all_of(mArgs->begin(), mArgs->end(), |
| [](const auto* arg) { return (*arg)->isJavaCompatible(); })) { |
| return false; |
| } |
| |
| if (!std::all_of(mResults->begin(), mResults->end(), |
| [](const auto* arg) { return (*arg)->isJavaCompatible(); })) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| const NamedReference<Type>* Method::canElideCallback() const { |
| // Can't elide callback for void or tuple-returning methods |
| if (mResults->size() != 1) { |
| return nullptr; |
| } |
| |
| const NamedReference<Type>* typedVar = mResults->at(0); |
| |
| if (typedVar->type().isElidableType()) { |
| return typedVar; |
| } |
| |
| return nullptr; |
| } |
| |
| const Location& Method::location() const { |
| return mLocation; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| bool TypedVarVector::add(NamedReference<Type>* v) { |
| if (mNames.emplace(v->name()).second) { |
| push_back(v); |
| return true; |
| } |
| return false; |
| } |
| |
| } // namespace android |
| |