/* * 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 "ConstantExpression.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 auto& constRet = static_cast<const Method*>(this)->getReferences(); std::vector<Reference<Type>*> ret(constRet.size()); std::transform(constRet.begin(), constRet.end(), ret.begin(), [](const auto* ref) { return const_cast<Reference<Type>*>(ref); }); return ret; } std::vector<const Reference<Type>*> Method::getReferences() const { std::vector<const Reference<Type>*> ret; ret.insert(ret.end(), mArgs->begin(), mArgs->end()); ret.insert(ret.end(), mResults->begin(), mResults->end()); return ret; } std::vector<Reference<Type>*> Method::getStrongReferences() { const auto& constRet = static_cast<const Method*>(this)->getStrongReferences(); std::vector<Reference<Type>*> ret(constRet.size()); std::transform(constRet.begin(), constRet.end(), ret.begin(), [](const auto* ref) { return const_cast<Reference<Type>*>(ref); }); return ret; } std::vector<const Reference<Type>*> Method::getStrongReferences() const { std::vector<const Reference<Type>*> ret; for (const auto* ref : getReferences()) { if (!ref->shallowGet()->isNeverStrongReference()) { ret.push_back(ref); } } return ret; } std::vector<ConstantExpression*> Method::getConstantExpressions() { const auto& constRet = static_cast<const Method*>(this)->getConstantExpressions(); std::vector<ConstantExpression*> ret(constRet.size()); std::transform(constRet.begin(), constRet.end(), ret.begin(), [](const auto* ce) { return const_cast<ConstantExpression*>(ce); }); return ret; } std::vector<const ConstantExpression*> Method::getConstantExpressions() const { std::vector<const ConstantExpression*> ret; for (const auto* annotation : *mAnnotations) { const auto& retAnnotation = annotation->getConstantExpressions(); ret.insert(ret.end(), retAnnotation.begin(), retAnnotation.end()); } return ret; } 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::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const { if (isHiddenFromJava()) { return true; } if (!std::all_of(mArgs->begin(), mArgs->end(), [&](const auto* arg) { return (*arg)->isJavaCompatible(visited); })) { return false; } if (!std::all_of(mResults->begin(), mResults->end(), [&](const auto* arg) { return (*arg)->isJavaCompatible(visited); })) { 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